C# 在C中运行时加载DLL#

C# 在C中运行时加载DLL#,c#,reflection,dll,C#,Reflection,Dll,我试图弄清楚如何在运行时在C#应用程序中导入并使用.dll。使用Assembly.LoadFile()我已经设法让我的程序加载dll(这部分确实在工作,因为我可以用ToString()获取类名),但是我无法从控制台应用程序内部使用“Output”方法。我正在编译.dll,然后将其移动到控制台的项目中。在CreateInstance和能够使用这些方法之间是否有额外的步骤 这是我的DLL中的类: namespace DLL { using System; public class

我试图弄清楚如何在运行时在C#应用程序中导入并使用.dll。使用Assembly.LoadFile()我已经设法让我的程序加载dll(这部分确实在工作,因为我可以用ToString()获取类名),但是我无法从控制台应用程序内部使用“Output”方法。我正在编译.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#调用。否则,必须使用反射或动态对象

反射

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)


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

您需要创建一个类型的实例来公开
输出
方法:

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()
返回一个没有输出方法的对象

看起来你来自动态编程语言?C#绝对不是这样,你想做的事情会很困难

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

如果您确实希望通过
assembly.load
加载程序集,则必须通过反射调用
c


类似于
type.GetMethod(“输出”).Invoke(c,null)应该能做到。

没那么难

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

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

这是非常简单的东西

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);
}
秒表秒表=新秒表();
对于(int i=0;i<4;i++)
{
stopwatch.Restart();
foreach(Directory.GetFiles(“.”、“*.dll”)中的var f)
装配。从(f)开始加载;
秒表;
控制台写入线(秒表延时百万秒);
}
输出: 34 0 0 0


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

注意,这会尝试对程序集中的每个类型调用
Output
,这可能会在找到“right”类之前抛出…@ReedCopsey同意,但对于他的简单示例,他的类型是唯一可见的类型。“在程序集外部可见的唯一类型是公共类型和嵌套在其他公共类型中的公共类型。”对于一个非常重要的示例,显然这将是一个问题……请结合两个示例:)这就是为什么经常使用接口,并且您可以进行特性检测,例如
idogdog=someInstance作为IDog并测试它是否不为null。将您的接口放在客户端共享的公共DLL中,任何动态加载的插件都必须实现该接口。这将允许您根据IDog接口编写客户端代码,并在编译时进行intellisense+强类型检查,而不是使用dynamic.@Tarek.Mh:这将需要编译时依赖于
Class1
。此时,您只需使用
newclass1()
。询问者明确指定了一个运行时依赖项
dynamic
允许程序完全不需要对
Class1
的编译时依赖性。非常感谢-这正是我要找的。我不敢相信这比其他答案的评分还高,因为它显示了动态关键词的使用。啊,现在我看到它也出现在DarkFalcon的答案中。不过,您的屏幕更短,更容易看到。:)哇,不知道为什么投票会被否决。我有一个生产应用程序在过去12年中一直在这样做。*耸耸肩*任何人需要一些代码来做这件事,给我一个消息。我会把我的部分产品代码打包并发送给大家。我想投票的结果可能与缺少示例和压缩语气有关。。。看起来你有一个完整答案的基础,所以不要害怕编辑更多的细节:)说“这是很简单的东西”有点粗鲁,这就是为什么你会被否决。我不是粗鲁或屈尊。。。。6年前。很明显,文本中的语调不清晰。这真的意味着很轻松。。。我还真的觉得这些年来我在那里有一个代码示例的链接,我不知道它去了哪里(假设它真的在那里,就像我记得的那样)\我不知道MethodInfo是如何工作的,但它似乎很有价值。我想说,你的答案有可能比目前接受的答案更好,但需要完成。如果你能抽出时间去做,我将不胜感激。如果是,请不要链接到代码示例。这些设备将来可能会损坏。最好是自己提供样本,可能还有一个指向源的链接或额外信息,以便继续阅读。
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);
}