web-dev-qa-db-fra.com

Puis-je charger un assembly .NET au moment de l'exécution et instancier un type en ne connaissant que le nom?

Est-il possible d'instancier un objet au moment de l'exécution si je ne dispose que du nom DLL et du nom de la classe, sans ajouter de référence à Assembly dans le projet? La classe implémente une interface, donc une fois que j'instancie la classe, je la jetterai ensuite sur l'interface.

Nom de l'Assemblée:

library.dll

Nom du type:

Company.Project.Classname


EDIT: Je n'ai pas le chemin absolu de la DLL, donc Assembly.LoadFile ne fonctionnera pas. La DLL peut se trouver à la racine de l'application, à system32 ou même chargée dans le GAC.

173
MegaByte

Oui. Vous devez utiliser Assembly.LoadFrom pour charger l’Assembly en mémoire. Vous pouvez alors utiliser Activator.CreateInstance pour créer une instance de votre type préféré. Vous devrez d'abord rechercher le type à l'aide de la réflexion. Voici un exemple simple:

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

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

object instanceOfMyType = Activator.CreateInstance(type);
_

Mise à jour

Lorsque vous avez le nom de fichier Assembly et le nom du type, vous pouvez utiliser Activator.CreateInstance(assemblyName, typeName) pour demander à la résolution de type .NET de le résoudre en un type. Vous pouvez encapsuler cela avec un test/catch afin qu'en cas d'échec, vous puissiez effectuer une recherche dans des répertoires dans lesquels vous pouvez stocker spécifiquement des assemblys supplémentaires sur lesquels il est possible que la recherche ne soit pas effectuée. Cela utiliserait la méthode précédente à ce stade.

216
Jeff Yates

Considérez les limites des différentes méthodes Load*. De la MSDN docs ...

LoadFile ne charge pas les fichiers dans le contexte LoadFrom et ne résout pas les dépendances à l'aide du chemin de chargement, comme le fait la méthode LoadFrom.

Plus d'informations sur les contextes de chargement sont disponibles dans la documentation LoadFrom .

35
Anthony Mastrean

Activator.CreateInstance devrait fonctionner.

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

Remarque: Le nom du type doit être le type complet.

Exemple:

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

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

J'ai trouvé cette question et certaines réponses très utiles, mais j'avais des problèmes de chemin. Cette réponse couvrirait donc le chargement de la bibliothèque en trouvant le chemin du répertoire bin.

Première solution:

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

Deuxième solution

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

Vous pouvez utiliser le même principe pour les interfaces (vous créez une classe mais transformez en interface), telles que:

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

Cet exemple est pour une application Web, mais similaire pourrait être utilisé pour une application de bureau, seul le chemin est résolu de manière différente, par exemple

Path.GetDirectoryName(Application.ExecutablePath)
6
Sofija

C'est facile.

Exemple de 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);
}

Voici un lien de référence

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

4
user3722131

À partir de Framework v4.5, vous pouvez utiliser Activator.CreateInstanceFrom () pour instancier facilement des classes dans des assemblys. L'exemple suivant montre comment l'utiliser et comment appeler une méthode en transmettant des paramètres et en obtenant une valeur de retour.

    // 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" } ));
3
afiorillo

Oui. Je n'ai aucun exemple que j'ai personnellement mis à disposition pour le moment. Je posterai plus tard quand j'en trouverai. Fondamentalement, vous utiliserez la réflexion pour charger l’Assemblée, puis tous les types dont vous avez besoin.

En attendant, ce lien devrait vous aider à démarrer:

tilisation de la réflexion pour charger des assemblys non référencés au moment de l'exécution

2
Giovanni Galbo
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();
2
abatishchev

En fonction de la nature intrinsèque de ce type de fonctionnalité dans votre projet, vous pouvez envisager quelque chose comme MEF , qui se chargera du chargement et de la liaison des composants.

2
Kent Boogaart

Vous pouvez charger un assembly à l'aide des méthodes * Assembly.Load **. En utilisant Activator.CreateInstance, vous pouvez créer de nouvelles instances du type souhaité. N'oubliez pas que vous devez utiliser le nom de type complet de la classe que vous souhaitez charger (par exemple, Namespace.SubNamespace.ClassName). En utilisant la méthode InvokeMember de la classe Type, vous pouvez appeler des méthodes sur le type.

De plus, prenez en compte le fait qu’une fois chargée, un assembly ne peut pas être déchargé avant le déchargement complet de l’AppDomain (il s’agit d’une fuite de mémoire).

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

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

dynamic instanceOfMyType = Activator.CreateInstance(type);

Ainsi, de cette manière, vous pouvez utiliser des fonctions sans extraire methodinfo, puis en les appelant. Vous ferez comme ceci instanceOfMyType.MethodName (); Mais vous ne pouvez pas utiliser Intellisense car les types dynamiques sont saisis au moment de l'exécution, pas au moment de la compilation.

2
David Mkheyan

Oui, vous souhaiterez utiliser la méthode Load statique sur la classe Assembly, puis appeler puis appeler la méthode CreateInstance sur l'instance Assembly qui vous a été renvoyée à partir de l'appel à Load.

En outre, vous pouvez appeler l'une des autres méthodes statiques en commençant par "Load" dans la classe Assembly, en fonction de vos besoins.

1
casperOne

Vous pouvez faire cela de cette façon:

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