Чи можу я завантажувати .NET збірку під час виконання та інстанціювати тип, знаючи лише ім’я?


178

Чи можливо інстанціювати об'єкт під час виконання, якщо у мене є лише ім'я DLL та ім'я класу, не додаючи посилання на збірку в проект? Клас реалізує інтерфейс, тому, як тільки я інстанціюю клас, я перекину його на інтерфейс.

Назва збірки:

library.dll

Назва типу:

Company.Project.Classname


EDIT: У мене немає абсолютного шляху DLL, тому Assembly.LoadFileне буде працювати. DLL може бути в корені програми, system32 або навіть завантажений у GAC.

Відповіді:


221

Так. Вам потрібно використовувати Assembly.LoadFromдля завантаження збірки в пам'ять, тоді ви можете використовувати Activator.CreateInstanceдля створення екземпляра бажаного типу. Вам потрібно буде спочатку переглянути тип за допомогою відображення. Ось простий приклад:

Assembly assembly = Assembly.LoadFrom("MyNice.dll");

Type type = assembly.GetType("MyType");

object instanceOfMyType = Activator.CreateInstance(type);

Оновлення

Якщо у вас є ім'я файлу збірки та ім'я типу, ви можете скористатись Activator.CreateInstance(assemblyName, typeName)запитом у роздільній здатності .NET, щоб вирішити це у тип. Ви можете обробити це за допомогою "try / catch", щоб, якщо це не вдалося, ви можете здійснити пошук каталогів, де ви можете спеціально зберігати додаткові збірки, які в іншому випадку можуть не шукатися. Це використовувало б попередній метод у той момент.


2
У мене немає абсолютного шляху до dll, тому assemlby.LoadFile ect. звичка працювати, будь-які інші ідеї?
MegaByte

@rp Завжди радий допомогти (і лише запізнився на рік!)
Джефф Йейтс

2
@MegaByte: LoadFrom відрізняється від LoadFile. Він вирішить ваші залежності, і він повинен вирішити ім'я DLL з відомих шляхів (GAC, каталог EXE тощо). Для отримання додаткової інформації див. MSDN.
Джефф Йейтс

1
Ще одна річ ... (мені знову) Гм, ви не можете просто мати "MyType" як ім'я типу, за ним слід іти NAMESPACE. Тож це було б точніше:Type type = assembly.GetType("MyNamespace"+"."+"MyType");
Cipi

1
@Cipi: Технічно тип - це повна назва простору імен (концепція простору імен - це зручність мови). Ви можете мати тип без простору імен в CLR - я просто надав надто спрощений приклад.
Джефф Ейтс

36

Розглянемо обмеження різних Load*методів. З документів MSDN ...

LoadFile не завантажує файли в контекст LoadFrom і не вирішує залежності, використовуючи шлях завантаження, як це робить метод LoadFrom.

Більше інформації про завантаження контекстів можна знайти в LoadFromдокументах.


19

Activator.CreateInstance повинен працювати.

IFace object = (IFace)Activator.CreateInstance( "AssemblyName",
                                                "TypeName" )
                               .Unwrap();

Примітка. Ім'я типу має бути повністю кваліфікованим типом.

Приклад:

var aray = (IList)Activator.CreateInstance("mscorlib","System.Collections.ArrayList").Unwrap();
aray.Add(10);

foreach (object obj in aray)
{
    Console.WriteLine(obj);
}

1
Лише зауваження з цього приводу: TypeNameмає бути повністю кваліфікованим. Мені довелося назвати це так: Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") І це повертає ObjectHandle. Щоб перейти до вашого інтерфейсу, вам потрібно це зробитиObjectHandle.UnWrap()
Ентоні Соттіл

7

Я знайшов це питання та деякі відповіді дуже корисними, однак у мене виникли проблеми із шляхами, тому ця відповідь охоплюватиме завантаження бібліотеки шляхом пошуку шляху до каталогу.

Перше рішення:

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFrom(assemblyPath);
Type T = assembly.GetType("Company.Project.Classname");
Company.Project.Classname instance = (Company.Project.Classname) Activator.CreateInstance(T);

Друге рішення

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFile(assemblyPath);
(Company.Project.Classname) instance = (Company.Project.Classname) assembly.CreateInstance("Company.Project.Classname");

Ви можете використовувати той же принцип для інтерфейсів (ви б створювали клас, але передавали інтерфейс), наприклад:

(Company.Project.Interfacename) instance = (Company.Project.Interfacename) assembly.CreateInstance("Company.Project.Classname");

Цей приклад призначений для веб-додатків, але подібний може бути використаний для настільних додатків, лише шлях вирішується, наприклад, іншим способом

Path.GetDirectoryName(Application.ExecutablePath)

5

Це легко.

Приклад з MSDN:

public static void Main()
{
    // Use the file name to load the assembly into the current
    // application domain.
    Assembly a = Assembly.Load("example");
    // Get the type to use.
    Type myType = a.GetType("Example");
    // Get the method to call.
    MethodInfo myMethod = myType.GetMethod("MethodA");
    // Create an instance.
    object obj = Activator.CreateInstance(myType);
    // Execute the method.
    myMethod.Invoke(obj, null);
}

Ось посилання на посилання

https://msdn.microsoft.com/en-us/library/25y1ya39.aspx


Це жахливий спосіб підтримати динамічне завантаження коду. МС завжди любив змушувати нас заводити занадто багато деталей.
Чіткіший

3

Починаючи з Framework v4.5, ви можете використовувати Activator.CreateInstanceFrom () для легкого інстанціювання класів в межах зборів. Наступний приклад показує, як його використовувати та як викликати метод, що передає параметри та отримує повернене значення.

    // Assuming moduleFileName contains full or valid relative path to assembly    
    var moduleInstance = Activator.CreateInstanceFrom(moduleFileName, "MyNamespace.MyClass");
    MethodInfo mi = moduleInstance.Unwrap().GetType().GetMethod("MyMethod");
    // Assuming the method returns a boolean and accepts a single string parameter
    bool rc = Convert.ToBoolean(mi.Invoke(moduleInstance.Unwrap(), new object[] { "MyParamValue" } ));

2

Так. У мене немає жодних прикладів, які я зробив особисто доступними зараз. Опублікую пізніше, коли знайду. В основному ви будете використовувати відображення для завантаження збірки, а потім для того, щоб витягнути будь-які типи, які вам потрібні.

Тим часом це посилання має розпочати:

Використання відображення для завантаження невирішених збірок під час виконання



2

Ви можете завантажити збірку методами * Assembly.Load **. Використовуючи Activator.CreateInstance, ви можете створювати нові екземпляри потрібного типу. Майте на увазі, що вам потрібно використовувати повне ім’я типу класу, який ви хочете завантажити (наприклад, Namespace.SubNamespace.ClassName ). Використання методу InvokeMember від типу класу ви можете викликати методи типу.

Крім того, врахуйте, що після завантаження збірка не може бути завантажена, поки також не буде завантажений весь AppDomain (це в основному витік пам'яті).


2

Залежно від того, наскільки цей функціонал є властивим вашому проекту, ви можете розглянути щось на кшталт MEF, яке піклується про завантаження та зв’язування компонентів для вас.


2
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");

Type type = assembly.GetType("MyType");

dynamic instanceOfMyType = Activator.CreateInstance(type);

Таким чином, ви можете використовувати функції, не отримуючи infoinfo, а потім викликаючи їх. Вам буде подобатися цей instanceOfMyType.MethodName (); Але ви не можете використовувати Intellisense, оскільки динамічні типи вводяться під час виконання, а не під час компіляції.


1

Так, ви хочете скористатися методом статичного завантаження в класі Assembly, а потім зателефонувати, а потім викликати метод CreateInstance в екземплярі Assembly, який повернувся вам від виклику Load.

Крім того, ви можете зателефонувати один із інших статичних методів, починаючи з "Завантажити" на класі складання, залежно від ваших потреб.


0

Це можна зробити так:

using System.Reflection;

Assembly MyDALL = Assembly.Load("DALL"); //DALL name of your assembly
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // name of your class
 object  obj = Activator.CreateInstance(MyLoadClass);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.