在C#中运行时加载DLL

时间:2013-08-21 16:02:29

标签: c# reflection dll

我试图找出如何在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();
        }
    }
}

6 个答案:

答案 0 :(得分:99)

成员必须在编译时可以解析才能直接从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();
        }
    }
}

答案 1 :(得分:33)

现在,您正在创建在程序集中定义的每种类型的实例。您只需创建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();
    }
}

答案 2 :(得分:11)

您需要创建一个公开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();
     }

答案 3 :(得分:0)

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

看起来你来自动态编程语言? C#绝对不是那样,而你想要做的事情将很难。

由于您是从特定位置加载特定的dll,可能只是想将其添加为控制台应用程序的参考?

如果您绝对想通过Assembly.Load加载程序集,则必须通过反思调用c上的任何成员

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

答案 4 :(得分: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

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

答案 5 :(得分:-2)

这并不困难。

您可以检查已加载对象的可用功能,如果找到了您要按名称查找的功能,则可以窥探其预期的参数(如果有)。如果它是您尝试查找的呼叫,则使用MethodInfo对象的Invoke方法调用它。

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

这很简单。