在 C# 中运行时加载 DLL

问题描述 投票:0回答:7

我正在尝试弄清楚如何在运行时在 C# 应用程序中导入和使用 .dll。使用 Assembly.LoadFile() 我已经设法让我的程序加载 dll(这部分肯定有效,因为我能够使用 ToString() 获取类的名称),但是我无法使用“输出”来自我的控制台应用程序内部的方法。我正在编译 .dll,然后将其移动到我的控制台项目中。在 CreateInstance 和能够使用这些方法之间是否有额外的步骤?

这是我的 DLL 中的类:

namespace DLL
{
    using System;

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

这是我要加载 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
7个回答
146
投票

成员必须在编译时可解析才能直接从 C# 调用。否则你必须使用反射或动态对象。

反思

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

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

46
投票

现在,您正在创建程序集中定义的每种类型的实例。您只需要创建

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

24
投票

您需要创建一个公开

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

0
投票

Activator.CreateInstance()
返回一个没有 Output 方法的对象。

看起来你是动态编程语言出身? C# 绝对不是那样,你试图做的事情会很困难。

由于您从特定位置加载特定的 dll,也许您只想将其添加为对控制台应用程序的引用?

如果您绝对想通过

Assembly.Load
加载程序集,则必须通过反射调用
c

上的任何成员

type.GetMethod("Output").Invoke(c, null);
这样的东西应该这样做。


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

这将加载可执行文件文件夹中存在的所有 DLL。

在我的例子中,我试图使用

Reflection
来查找一个类的所有子类,即使在其他 DLL 中也是如此。这行得通,但我不确定这是否是最好的方法。

编辑:我计时了,它似乎只在第一次加载它们。

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

输出: 34 0 0 0

因此,为了以防万一,可以在任何反射搜索之前运行该代码。


0
投票

几年后...

以下是对我有用的方法,用于从 DLL 获取属性值。在 GetType() 方法调用中,我不得不使用 namespace.classname.


Assembly dllAsm = Assembly.LoadFile(@"C:\THE\FULL\PATH\TO\YOUR\DLL\yourdynolib.dll");

Type yourType = dllAsm.GetType("YourNamespace.YourClassName");
var yourInstance = Activator.CreateInstance(yourType);

PropertyInfo piYourType = null;
piYourType = yourType.GetProperty("YourPropName");

string yourPropValue = (string)piYourType.GetValue(yourInstance);

-1
投票

没那么难。

您可以检查加载对象的可用功能,如果您通过名称找到您要查找的功能,则探听其预期参数(如果有)。如果它是您要查找的调用,则使用 MethodInfo 对象的 Invoke 方法调用它。

另一个选择是简单地将外部对象构建到一个接口,并将加载的对象转换到该接口。如果成功,则本地调用该函数。

这是很简单的事情。

© www.soinside.com 2019 - 2024. All rights reserved.