简体   繁体   English

在 C# 中在运行时加载 DLL

[英]Loading DLLs at runtime in C#

I am trying to figure out how you could go about importing and using a .dll at runtime inside a C# application.我想弄清楚如何在 C# 应用程序中在运行时导入和使用 .dll。 Using Assembly.LoadFile() I have managed to get my program to load the dll (this part is definitely working as I am able to get the name of the class with ToString()), however I am unable to use the 'Output' method from inside my console application.使用 Assembly.LoadFile() 我已经设法让我的程序加载 dll(这部分肯定有效,因为我能够使用 ToString() 获取类的名称),但是我无法使用“输出”我的控制台应用程序中的方法。 I am compiling the .dll then moving it into my console's project.我正在编译 .dll,然后将其移动到我的控制台项目中。 Is there an extra step between CreateInstance and then being able to use the methods?在 CreateInstance 和能够使用这些方法之间是否有额外的步骤?

This is the class in my DLL:这是我的 DLL 中的类:

namespace DLL
{
    using System;

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

and here is the application I want to load the DLL这是我要加载 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();
        }
    }
}

Members must be resolvable at compile time to be called directly from C#.成员必须在编译时可解析才能直接从 C# 调用。 Otherwise you must use reflection or dynamic objects.否则,您必须使用反射或动态对象。

Reflection反射

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

Dynamic (.NET 4.0)动态 (.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();
        }
    }
}

Right now, you're creating an instance of every type defined in the assembly .现在,您正在为程序集中定义每个类型创建一个实例。 You only need to create a single instance of Class1 in order to call the method:您只需要创建Class1的单个实例即可调用该方法:

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

You need to create an instance of the type that expose the Output method:您需要创建一个公开Output方法的类型的实例:

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

Activator.CreateInstance() returns an object, which doesn't have an Output method. Activator.CreateInstance()返回一个对象,该对象没有 Output 方法。

It looks like you come from dynamic programming languages?看起来你来自动态编程语言? C# is definetly not that, and what you are trying to do will be difficult. C# 绝对不是那样,你想要做的事情会很困难。

Since you are loading a specific dll from a specific location, maybe you just want to add it as a reference to your console application?由于您是从特定位置加载特定 dll,也许您只想将其添加为对您的控制台应用程序的引用?

If you absolutely want to load the assembly via Assembly.Load , you will have to go via reflection to call any members on c如果您绝对想通过Assembly.Load加载程序Assembly.Load ,则必须通过反射调用c任何成员

Something like type.GetMethod("Output").Invoke(c, null);类似于type.GetMethod("Output").Invoke(c, null); should do it.应该这样做。

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

That loads all the DLLs present in your executable's folder.这会加载可执行文件文件夹中的所有 DLL。

In my case I was trying to use Reflection to find all subclasses of a class, even in other DLLs.就我而言,我试图使用Reflection来查找一个类的所有子类,即使在其他 DLL 中也是如此。 This worked, but I'm not sure if it's the best way to do it.这有效,但我不确定这是否是最好的方法。

EDIT: I timed it, and it only seems to load them the first time.编辑:我计时,它似乎只在第一次加载它们。

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

Output: 34 0 0 0输出:34 0 0 0

So one could potentially run that code before any Reflection searches just in case.因此,为了以防万一,可以在任何反射搜索之前运行该代码。

It's not so difficult.这不是那么困难。

You can inspect the available functions of the loaded object, and if you find the one you're looking for by name, then snoop its expected parms, if any.您可以检查已加载对象的可用功能,如果您按名称找到了您要查找的功能,则窥探其预期参数(如果有)。 If it's the call you're trying to find, then call it using the MethodInfo object's Invoke method.如果是您要查找的调用,则使用 MethodInfo 对象的 Invoke 方法调用它。

Another option is to simply build your external objects to an interface, and cast the loaded object to that interface.另一种选择是简单地将外部对象构建到接口,并将加载的对象转换为该接口。 If successful, call the function natively.如果成功,则本地调用该函数。

This is pretty simple stuff.这是很简单的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM