Правильный способ загрузки сборки, поиска метода вызова и вызова ()

Пример программы консоли.

class Program { static void Main(string[] args) { // ... code to build dll ... not written yet ... Assembly assembly = Assembly.LoadFile(@"C:\dyn.dll"); // don't know what or how to cast here // looking for a better way to do next 3 lines IRunnable r = assembly.CreateInstance("TestRunner"); if (r == null) throw new Exception("broke"); r.Run(); } } 

Я хочу динамически строить сборку (DLL), а затем загружать сборку, создавать экземпляр classа и вызывать метод Run () этого classа. Должен ли я попробовать что-то отличить class TestRunner? Не знаете, как типы в одной сборке (динамическом коде) будут знать о моих типах в моем (статическое приложение сборки / оболочки). Лучше просто использовать несколько строк кода отражения, чтобы вызвать Run () только на одном объекте? Как должен выглядеть этот код?

ОБНОВЛЕНИЕ: Уильям Эдмондсон – см. Комментарий

5 Solutions collect form web for “Правильный способ загрузки сборки, поиска метода вызова и вызова ()”

Использовать AppDomain

Безопаснее и гибче загружать сборку в свой собственный AppDomain .

Поэтому вместо ответа, приведенного ранее :

 var asm = Assembly.LoadFile(@"C:\myDll.dll"); var type = asm.GetType("TestRunner"); var runnable = Activator.CreateInstance(type) as IRunnable; if (runnable == null) throw new Exception("broke"); runnable.Run(); 

Я предложил бы следующее (адаптированное из этого ответа на соответствующий вопрос ):

 var domain = AppDomain.CreateDomain("NewDomainName"); var t = typeof(TypeIWantToLoad); var runnable = domain.CreateInstanceFromAndUnwrap(@"C:\myDll.dll", t.Name) as IRunnable; if (runnable == null) throw new Exception("broke"); runnable.Run(); 

Теперь вы можете разгружать сборку и иметь разные настройки безопасности.

Если вы хотите еще большую гибкость и мощность для динамической загрузки и выгрузки сборок, вы должны посмотреть на управляемую инфраструктуру надстроек (то есть пространство имен System.AddIn ). Для получения дополнительной информации см. Эту статью о надстройках и расширяемости в MSDN .

Если у вас нет доступа к TestRunner типа TestRunner в вызывающей сборке (похоже, это не так), вы можете вызвать метод следующим образом:

 Assembly assembly = Assembly.LoadFile(@"C:\dyn.dll"); Type type = assembly.GetType("TestRunner"); var obj = Activator.CreateInstance(type); // Alternately you could get the MethodInfo for the TestRunner.Run method type.InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); 

Если у вас есть доступ к IRunnable интерфейса IRunnable , вы можете IRunnable свой экземпляр на него (а не тип TestRunner , который реализован в динамически созданной или загруженной сборке, правильно?):

  Assembly assembly = Assembly.LoadFile(@"C:\dyn.dll"); Type type = assembly.GetType("TestRunner"); IRunnable runnable = Activator.CreateInstance(type) as IRunnable; if (runnable == null) throw new Exception("broke"); runnable.Run(); 

Я выполняю именно то, что вы ищете в моем движке правил, который использует CS-Script для динамической компиляции, загрузки и запуска C #. Он должен быть легко переводим в то, что вы ищете, и я приведу пример. Во-первых, код (урезанный):

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using CSScriptLibrary; namespace RulesEngine { ///  /// Make sure  is an interface, not just any type of class. /// /// Should be enforced by the compiler, but just in case it's not, here's your warning. ///  ///  public class RulesEngine where T : class { public RulesEngine(string rulesScriptFileName, string classToInstantiate) : this() { if (rulesScriptFileName == null) throw new ArgumentNullException("rulesScriptFileName"); if (classToInstantiate == null) throw new ArgumentNullException("classToInstantiate"); if (!File.Exists(rulesScriptFileName)) { throw new FileNotFoundException("Unable to find rules script", rulesScriptFileName); } RulesScriptFileName = rulesScriptFileName; ClassToInstantiate = classToInstantiate; LoadRules(); } public T @Interface; public string RulesScriptFileName { get; private set; } public string ClassToInstantiate { get; private set; } public DateTime RulesLastModified { get; private set; } private RulesEngine() { @Interface = null; } private void LoadRules() { if (!File.Exists(RulesScriptFileName)) { throw new FileNotFoundException("Unable to find rules script", RulesScriptFileName); } FileInfo file = new FileInfo(RulesScriptFileName); DateTime lastModified = file.LastWriteTime; if (lastModified == RulesLastModified) { // No need to load the same rules twice. return; } string rulesScript = File.ReadAllText(RulesScriptFileName); Assembly compiledAssembly = CSScript.LoadCode(rulesScript, null, true); @Interface = compiledAssembly.CreateInstance(ClassToInstantiate).AlignToInterface(); RulesLastModified = lastModified; } } } 

Это займет интерфейс типа T, скомпилирует файл .cs в сборку, создаст экземпляр classа заданного типа и выровняем этот экземпляр classа с интерфейсом T. В принципе, вам просто нужно убедиться, что экземпляр classа реализует этот интерфейс. Я использую свойства для настройки и доступа ко всем, например:

 private RulesEngine rulesEngine; public RulesEngine RulesEngine { get { if (null == rulesEngine) { string rulesPath = Path.Combine(Application.StartupPath, "Rules.cs"); rulesEngine = new RulesEngine(rulesPath, typeof(Rules).FullName); } return rulesEngine; } } public IRulesEngine RulesEngineInterface { get { return RulesEngine.Interface; } } 

Для вашего примера вы хотите вызвать Run (), поэтому я бы создал интерфейс, который определяет метод Run (), например:

 public interface ITestRunner { void Run(); } 

Затем создайте class, который его реализует, например:

 public class TestRunner : ITestRunner { public void Run() { // implementation goes here } } 

Измените имя RulesEngine на нечто вроде TestHarness и задайте свои свойства:

 private TestHarness testHarness; public TestHarness TestHarness { get { if (null == testHarness) { string sourcePath = Path.Combine(Application.StartupPath, "TestRunner.cs"); testHarness = new TestHarness(sourcePath , typeof(TestRunner).FullName); } return testHarness; } } public ITestRunner TestHarnessInterface { get { return TestHarness.Interface; } } 

Затем в любом месте, которое вы хотите назвать, вы можете просто запустить:

 ITestRunner testRunner = TestHarnessInterface; if (null != testRunner) { testRunner.Run(); } 

Это, вероятно, отлично подойдет для плагиновой системы, но мой код как есть, ограничен загрузкой и запуском одного файла, так как все наши правила находятся в одном исходном файле C #. Я бы подумал, что было бы довольно легко изменить его, чтобы просто передать файл типа / источника для каждого из них, который вы хотели запустить. Вам просто нужно переместить код из получателя в метод, который принял эти два параметра.

Кроме того, используйте свой IRunnable вместо ITestRunner.

Вам нужно будет использовать reflection, чтобы получить тип «TestRunner». Используйте метод Assembly.GetType.

 class Program { static void Main(string[] args) { Assembly assembly = Assembly.LoadFile(@"C:\dyn.dll"); Type type = assembly.GetType("TestRunner"); var obj = (TestRunner)Activator.CreateInstance(type); obj.Run(); } } 

Когда вы создаете сборку, вы можете вызвать AssemblyBuilder.SetEntryPoint , а затем вернуть ее из свойства Assembly.EntryPoint чтобы вызвать ее.

Имейте в виду, что вы захотите использовать эту подпись и обратите внимание, что ее не нужно называть Main :

 static void Run(string[] args) 
  • Можно ли установить частную собственность через reflection?
  • В чем разница между динамическим прокси JDK и CGLib?
  • Как получить значение свойства на основе имени
  • Имя свойства INotifyPropertyChanged - hardcode vs reflection?
  • Установка свойства путем отражения со строковым значением
  • Избегание instanceof в Java
  • Можно ли задать значение свойства с помощью Reflection?
  • Как я могу динамически добавлять поле в class в C #
  • Как проверить, является ли тип примитивным
  • Я хочу получить тип переменной во время выполнения
  • Как перечислить все функции в модуле Python?
  • Interesting Posts

    Печать TCP / IP-порта в TXT-файл непосредственно из Windows 10 (без дополнительного программного обеспечения)

    Как написать сценарий PowerShell, который принимает ввод конвейера?

    Могут ли сокеты TCP и UDP использовать один и тот же порт?

    Фрагменты onResume из заднего стека

    Как получить разницу между двумя датами в Год / Месяц / Неделя / День?

    Почему у этого метода Java есть два типа возврата?

    Ubuntu Netbook Remix на USB?

    Инструмент командной строки для сброса версии Windows DLL?

    Отображение столбца PostgreSQL JSON для типа значения Hibernate

    Как сказать jacksonу игнорировать поле во время сериализации, если его значение равно нулю?

    Как заставить OneGet / PackageManagement работать в Windows 10 Home?

    Ckeditor update textarea

    C # ошибка с нулевой строкой

    Как бы вы определили пул goroutines, которые будут выполнены сразу в Голанге?

    Должны ли мы переключиться на использование асинхронного ввода-вывода по умолчанию?

    Давайте будем гением компьютера.