101 votes

Chargement des DLL au moment de l'exécution en C#

J'essaie de comprendre comment on peut importer et utiliser une dll au moment de l'exécution dans une application C#. En utilisant Assembly.LoadFile(), j'ai réussi à faire en sorte que mon programme charge la dll (cette partie fonctionne sans aucun doute puisque je suis capable d'obtenir le nom de la classe avec ToString()), mais je suis incapable d'utiliser la méthode 'Output' à l'intérieur de mon application console. Je compile la dll, puis je la 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 ?

C'est la classe dans ma DLL :

namespace DLL
{
    using System;

    public class Class1
    {
        public void Output(string s)
        {
            Console.WriteLine(s);
        }
    }
}

et voici l'application dans laquelle je veux 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();
        }
    }
}

138voto

Dark Falcon Points 15609

Les membres doivent être résolubles au moment de la compilation pour être appelés directement depuis le C#. Sinon, vous devez utiliser la réflexion ou les 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();
        }
    }
}

42voto

Reed Copsey Points 315315

Pour l'instant, vous créez une instance de chaque type défini dans l'assemblage . Vous n'avez besoin de créer qu'une seule instance de Class1 afin d'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();
    }
}

23voto

Alberto Points 5865

Vous devez créer une instance du type qui expose la fonction 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();
     }

0voto

Fredrik Points 97

Activator.CreateInstance() renvoie un objet, qui n'a pas de méthode Output.

On dirait que vous venez des langages de programmation dynamiques ? Le C# n'en est certainement pas un, et ce que vous essayez de faire sera difficile.

Puisque vous chargez une dll spécifique à partir d'un emplacement spécifique, peut-être voulez-vous simplement l'ajouter comme référence à votre application console ?

Si vous voulez absolument charger l'assemblage via Assembly.Load vous devrez passer par la réflexion pour appeler les membres sur le site. c

Quelque chose comme type.GetMethod("Output").Invoke(c, null); devrait le faire.

0voto

Samuel Cabrera Points 65
foreach (var f in Directory.GetFiles(".", "*.dll"))
            Assembly.LoadFrom(f);

Cela charge toutes les DLLs 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 procéder.

EDIT : J'ai chronométré, et il semble que ça ne les charge 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 peut donc potentiellement exécuter ce code avant toute recherche Reflection, au cas où.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X