Posso caricare un assembly .NET in fase di esecuzione e creare un'istanza di un tipo conoscendo solo il nome?


178

È possibile creare un'istanza di un oggetto in fase di esecuzione se ho solo il nome DLL e il nome classe, senza aggiungere un riferimento all'assembly nel progetto? La classe implementa un'interfaccia, quindi una volta istanziata la classe, la lancerò sull'interfaccia.

Nome dell'Assemblea:

library.dll

Digitare il nome:

Company.Project.Classname


EDIT: Non ho il percorso assoluto della DLL, quindi Assembly.LoadFilenon funzionerà. La DLL potrebbe trovarsi nell'applicazione root, system32 o persino caricata nel GAC.

Risposte:


221

Sì. È necessario utilizzare Assembly.LoadFromper caricare l'assembly in memoria, quindi è possibile utilizzare Activator.CreateInstanceper creare un'istanza del tipo preferito. Dovrai prima cercare il tipo usando la riflessione. Qui c'è un semplice esempio:

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

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

object instanceOfMyType = Activator.CreateInstance(type);

Aggiornare

Quando si dispone del nome del file di assieme e del nome del tipo, è possibile utilizzare Activator.CreateInstance(assemblyName, typeName)per chiedere alla risoluzione del tipo .NET di risolverlo in un tipo. È possibile racchiuderlo con un tentativo / catch in modo che, se fallisce, è possibile eseguire una ricerca di directory in cui è possibile memorizzare in modo specifico altri assembly che altrimenti non potrebbero essere cercati. Questo userebbe il metodo precedente a quel punto.


2
Non ho il percorso assoluto della DLL, quindi assemlby.LoadFile ect. non funzionerà, altre idee?
MegaByte il

@rp Sempre felice di aiutarti (e solo un anno dopo lo ha detto!)
Jeff Yates,

2
@MegaByte: LoadFrom è diverso da LoadFile. Risolverà le tue dipendenze e dovrebbe risolvere il nome DLL da percorsi noti (GAC, directory exe, ecc.) Vedi MSDN per ulteriori informazioni.
Jeff Yates,

1
Un'altra cosa ... (di nuovo io) Uhm, non puoi semplicemente avere "MyType" come nome del tipo, deve essere seguito da NAMESPACE. Quindi questo sarebbe più preciso:Type type = assembly.GetType("MyNamespace"+"."+"MyType");
Cipi,

1
@Cipi: tecnicamente, un tipo è il suo nome con spazio completo (il concetto di spazio dei nomi è una comodità linguistica). Puoi avere un tipo senza spazio dei nomi all'interno del CLR - Stavo solo fornendo un esempio eccessivamente semplificato.
Jeff Yates,

36

Considera i limiti dei diversi Load*metodi. Dai documenti MSDN ...

LoadFile non carica i file nel contesto LoadFrom e non risolve le dipendenze utilizzando il percorso di caricamento, come fa il metodo LoadFrom.

Ulteriori informazioni su Load Contexts sono disponibili nei LoadFromdocumenti.


19

Activator.CreateInstance dovrebbe funzionare.

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

Nota: il nome del tipo deve essere del tipo completo.

Esempio:

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

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

1
Solo una nota su questo: TypeNamedeve essere pienamente qualificato. Ho dovuto chiamarlo così: Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") E questo restituisce un ObjectHandle. Per arrivare alla tua interfaccia devi fareObjectHandle.UnWrap()
Anthony Sottile l'

7

Ho trovato questa domanda e alcune risposte molto utili, tuttavia ho avuto problemi di percorso, quindi questa risposta coprirebbe il caricamento della libreria trovando il percorso della directory bin.

Prima soluzione:

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);

Seconda soluzione

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");

Puoi usare lo stesso principio per le interfacce (dovresti creare una classe ma eseguire il casting per l'interfaccia), come ad esempio:

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

Questo esempio è per l'applicazione Web ma simile potrebbe essere usato per l'applicazione Desktop, ad esempio solo il percorso viene risolto in modo diverso

Path.GetDirectoryName(Application.ExecutablePath)

5

È facile.

Esempio da 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);
}

Ecco un link di riferimento

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


È un modo orribile per supportare il caricamento dinamico del codice. A MS è sempre piaciuto costringerci ad entrare in troppi dettagli.
Più chiaro l'

3

A partire da Framework v4.5 è possibile utilizzare Activator.CreateInstanceFrom () per creare facilmente un'istanza di classi all'interno di assiemi. L'esempio seguente mostra come usarlo e come chiamare un metodo passando parametri e ottenendo valore di ritorno.

    // 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
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();

2

È possibile caricare un assembly utilizzando i metodi * Assembly.Load **. Utilizzando Activator.CreateInstance è possibile creare nuove istanze del tipo desiderato. Tieni presente che devi utilizzare il nome completo del tipo della classe che desideri caricare (ad esempio Namespace.SubNamespace.ClassName ). Utilizzando il metodo InvokeMember del tipo classe è possibile richiamare metodi sul tipo.

Inoltre, tieni presente che una volta caricato, un assembly non può essere scaricato fino a quando non viene scaricato anche l'intero AppDomain (questa è fondamentalmente una perdita di memoria).


2

A seconda di quanto intrinseco sia questo tipo di funzionalità per il tuo progetto, potresti prendere in considerazione qualcosa come MEF che si occuperà del caricamento e del collegamento dei componenti per te.


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

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

dynamic instanceOfMyType = Activator.CreateInstance(type);

Quindi in questo modo puoi usare le funzioni non per ottenere methodinfo e quindi invocarlo. Ti piacerà questa istanzaOfMyType.MethodName (); Ma non è possibile utilizzare Intellisense perché i tipi dinamici vengono digitati in fase di esecuzione, non in fase di compilazione.


1

Sì, è necessario utilizzare il metodo Load statico sulla classe Assembly, quindi chiamare e chiamare il metodo CreateInstance sull'istanza Assembly restituita dalla chiamata a Load.

Inoltre, è possibile chiamare uno degli altri metodi statici che iniziano con "Carica" ​​nella classe Assembly, a seconda delle esigenze.


0

Puoi fare queste cose in questo modo:

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.