我正在尝试弄清楚如何在运行时在 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# 调用。否则你必须使用反射或动态对象。
反思
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();
}
}
}
现在,您正在创建程序集中定义的每种类型的实例。您只需要创建
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();
}
}
您需要创建一个公开
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()
返回一个没有 Output 方法的对象。
看起来你是动态编程语言出身? C# 绝对不是那样,你试图做的事情会很困难。
由于您从特定位置加载特定的 dll,也许您只想将其添加为对控制台应用程序的引用?
如果您绝对想通过
Assembly.Load
加载程序集,则必须通过反射调用c
上的任何成员
像
type.GetMethod("Output").Invoke(c, null);
这样的东西应该这样做。
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
因此,为了以防万一,可以在任何反射搜索之前运行该代码。
几年后...
以下是对我有用的方法,用于从 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);
没那么难。
您可以检查加载对象的可用功能,如果您通过名称找到您要查找的功能,则探听其预期参数(如果有)。如果它是您要查找的调用,则使用 MethodInfo 对象的 Invoke 方法调用它。
另一个选择是简单地将外部对象构建到一个接口,并将加载的对象转换到该接口。如果成功,则本地调用该函数。
这是很简单的事情。