J'essaie de comprendre comment vous pourriez importer et utiliser un .dll au moment de l'exécution dans une application C #. En utilisant Assembly.LoadFile (), j'ai réussi à obtenir mon programme pour charger la dll (cette partie fonctionne certainement car je suis capable d'obtenir le nom de la classe avec ToString ()), mais je ne peux pas utiliser le 'Output' méthode depuis l'intérieur de mon application console. Je compile le .dll puis je le déplace dans le projet de ma console. Y a-t-il une étape supplémentaire entre CreateInstance et la possibilité d'utiliser les méthodes?
Voici la classe dans ma DLL:
namespace DLL
{
using System;
public class Class1
{
public void Output(string s)
{
Console.WriteLine(s);
}
}
}
et voici l'application que je souhaite charger la DLL
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
c.Output(@"Hello");
}
Console.ReadLine();
}
}
}
c#
reflection
dll
danbroooks
la source
la source
Réponses:
Les membres doivent pouvoir être résolus au moment de la compilation pour être appelés directement à partir de C #. Sinon, vous devez utiliser la réflexion ou des objets dynamiques.
Réflexion
namespace ConsoleApplication1 { using System; using System.Reflection; class Program { static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); foreach(Type type in DLL.GetExportedTypes()) { var c = Activator.CreateInstance(type); type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {@"Hello"}); } Console.ReadLine(); } } }
Dynamique (.NET 4.0)
namespace ConsoleApplication1 { using System; using System.Reflection; class Program { static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); foreach(Type type in DLL.GetExportedTypes()) { dynamic c = Activator.CreateInstance(type); c.Output(@"Hello"); } Console.ReadLine(); } } }
la source
Output
tous les types de l'assemblage, ce qui sera probablement lancé avant que la classe «correcte» ne soit trouvée ...IDog dog = someInstance as IDog;
et tester si elle n'est pas nulle. Placez vos interfaces dans une DLL commune partagée par les clients, et tout plugin qui sera chargé dynamiquement doit implémenter cette interface. Cela vous permettra ensuite de coder votre client avec l'interface IDog et d'avoir une vérification de type intellisense + strong au moment de la compilation plutôt que d'utiliser Dynamic.Class1
. À ce stade, vous pouvez simplement utilisernew Class1()
. Le demandeur a explicitement spécifié une dépendance d'exécution.dynamic
permet au programme de ne pas exiger du tout une dépendance à la compilation surClass1
.À l'heure actuelle, vous créez une instance de chaque type défini dans l'assemblage . Il vous suffit de créer une seule instance de
Class1
pour appeler la méthode:class Program { static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); var theType = DLL.GetType("DLL.Class1"); var c = Activator.CreateInstance(theType); var method = theType.GetMethod("Output"); method.Invoke(c, new object[]{@"Hello"}); Console.ReadLine(); } }
la source
Vous devez créer une instance du type qui expose la
Output
méthode:static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); var class1Type = DLL.GetType("DLL.Class1"); //Now you can use reflection or dynamic to call the method. I will show you the dynamic way dynamic c = Activator.CreateInstance(class1Type); c.Output(@"Hello"); Console.ReadLine(); }
la source
Activator.CreateInstance()
renvoie un objet qui n'a pas de méthode Output.On dirait que vous venez de langages de programmation dynamiques? C # n'est certainement pas cela, et ce que vous essayez de faire sera difficile.
Puisque vous chargez une dll spécifique à partir d'un emplacement spécifique, vous souhaitez peut-être simplement l'ajouter comme référence à votre application console?
Si vous souhaitez absolument charger l'assembly via
Assembly.Load
, vous devrez passer par la réflexion pour appeler les membres surc
Quelque chose comme
type.GetMethod("Output").Invoke(c, null);
ça devrait le faire.la source
foreach (var f in Directory.GetFiles(".", "*.dll")) Assembly.LoadFrom(f);
Cela charge toutes les DLL présentes dans le dossier de votre exécutable.
Dans mon cas, j'essayais d'utiliser
Reflection
pour trouver toutes les sous-classes d'une classe, même dans d'autres DLL. Cela a fonctionné, mais je ne suis pas sûr que ce soit la meilleure façon de le faire.EDIT: Je l'ai chronométré, et il ne semble les charger que la première fois.
Stopwatch stopwatch = new Stopwatch(); for (int i = 0; i < 4; i++) { stopwatch.Restart(); foreach (var f in Directory.GetFiles(".", "*.dll")) Assembly.LoadFrom(f); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); }
Sortie: 34 0 0 0
On pourrait donc potentiellement exécuter ce code avant toute recherche Reflection au cas où.
la source
Ce n'est pas si difficile.
Vous pouvez inspecter les fonctions disponibles de l'objet chargé, et si vous trouvez celle que vous recherchez par son nom, fouillez ses paramètres attendus, le cas échéant. Si c'est l'appel que vous essayez de trouver, appelez-le à l'aide de la méthode Invoke de l'objet MethodInfo.
Une autre option consiste simplement à créer vos objets externes dans une interface et à convertir l'objet chargé dans cette interface. En cas de succès, appelez la fonction de manière native.
Ce sont des choses assez simples.
la source