在运行时动态加载 DLL 并创建接口实现的实例
Load DLL and create instances of interface implementations dynamically at runtime
我有很多 DLL 连接器。每个DLL里面的方法太多了。但每个 DLL 连接器包含以下两个方法(byte[] Document = GetDocument(string, string, string); 和 byte[] Image = GetImage(string, string, string);).
我想做的是:
1- Select 运行时的 DLL 文件。
2- 填写三个字符串。
3- 将三个字符串传递给插入的 DLL 中的方法(上面提到的)以接收返回的文件。
我只想知道怎么调用DLL里面的方法
感谢任何帮助。
你必须使用反射(当然)。
看看 Assembly
class.
您可以例如使用 Assembly.LoadFile
或 Assembly.LoadFrom
加载程序集。
要激活包含在组件中的类型以调用其成员,您可以使用 Assembly.CreateInstance
:
Assembly assembly = Assembly.LoadFile("C:\bin\runtime.dll");
TypeInsideAssembly instanceOfTypeInsideAssembly = (TypeInsideAssembly) assembly.CreateInstance(typeOf(TypeInsideAssembly));
instanceOfTypeInsideAssembly.InvokeMethod(params);
如果构造函数需要参数,您可以使用适当的 overload CreateInstance(String, Boolean, BindingFlags, Binder, Object[], CultureInfo, Object[])
.
例子
以下通用示例使用反射创建位于指定程序集中的 TBase
实例,需要无参数构造函数。 TBase
可以是 class(基础 class)或接口。
不是 public
或未定义无参数构造函数的类型将被忽略。
private IEnumerable<TBase> GetInstancesOf<TBase>(string assemblyFilePath)
{
var assembly = Assembly.LoadFile(assemblyFilePath);
// Get all public types that are defined in this assembly
Type[] publicTypes = assembly.GetExportedTypes();
// Filter all public types in assembly and return only types...
IEnumerable<TBase> documentProviders = publicTypes
// ...that are not an interface (as we can't create instances of interfaces)...
.Where(publicType => !publicType.IsInterface
// ...AND that are not an abstract class (as we can't create instances of abstract types)...
&& !publicType.IsAbstract
// ...AND that have a public parameterless constructor...
&& publicType.GetConstructor(Type.EmptyTypes) != null
// ...AND are a subtype of TBase. Note that TBase can be a base class or interface
&& typeof(TBase).IsAssignableFrom(publicType))
// Take each collected type and create an instance of those types
.Select(concreteInterfaceType => assembly.CreateInstance(concreteInterfaceType.FullName))
// Since CreateInstance() returns object, cast each created instance to the common subtype TBase
.Cast<TBase>();
return documentProviders;
}
用法
private void HandleDocuments(string assemblyFilePath)
{
foreach (IClientMethods documentProvider in GetInstancesOf<IClientMethods>(assemblyFilePath))
{
byte[] document = documentProvider.GetDocument(...);
}
}
我有很多 DLL 连接器。每个DLL里面的方法太多了。但每个 DLL 连接器包含以下两个方法(byte[] Document = GetDocument(string, string, string); 和 byte[] Image = GetImage(string, string, string);).
我想做的是: 1- Select 运行时的 DLL 文件。 2- 填写三个字符串。 3- 将三个字符串传递给插入的 DLL 中的方法(上面提到的)以接收返回的文件。
我只想知道怎么调用DLL里面的方法
感谢任何帮助。
你必须使用反射(当然)。
看看 Assembly
class.
您可以例如使用 Assembly.LoadFile
或 Assembly.LoadFrom
加载程序集。
要激活包含在组件中的类型以调用其成员,您可以使用 Assembly.CreateInstance
:
Assembly assembly = Assembly.LoadFile("C:\bin\runtime.dll");
TypeInsideAssembly instanceOfTypeInsideAssembly = (TypeInsideAssembly) assembly.CreateInstance(typeOf(TypeInsideAssembly));
instanceOfTypeInsideAssembly.InvokeMethod(params);
如果构造函数需要参数,您可以使用适当的 overload CreateInstance(String, Boolean, BindingFlags, Binder, Object[], CultureInfo, Object[])
.
例子
以下通用示例使用反射创建位于指定程序集中的 TBase
实例,需要无参数构造函数。 TBase
可以是 class(基础 class)或接口。
不是 public
或未定义无参数构造函数的类型将被忽略。
private IEnumerable<TBase> GetInstancesOf<TBase>(string assemblyFilePath)
{
var assembly = Assembly.LoadFile(assemblyFilePath);
// Get all public types that are defined in this assembly
Type[] publicTypes = assembly.GetExportedTypes();
// Filter all public types in assembly and return only types...
IEnumerable<TBase> documentProviders = publicTypes
// ...that are not an interface (as we can't create instances of interfaces)...
.Where(publicType => !publicType.IsInterface
// ...AND that are not an abstract class (as we can't create instances of abstract types)...
&& !publicType.IsAbstract
// ...AND that have a public parameterless constructor...
&& publicType.GetConstructor(Type.EmptyTypes) != null
// ...AND are a subtype of TBase. Note that TBase can be a base class or interface
&& typeof(TBase).IsAssignableFrom(publicType))
// Take each collected type and create an instance of those types
.Select(concreteInterfaceType => assembly.CreateInstance(concreteInterfaceType.FullName))
// Since CreateInstance() returns object, cast each created instance to the common subtype TBase
.Cast<TBase>();
return documentProviders;
}
用法
private void HandleDocuments(string assemblyFilePath)
{
foreach (IClientMethods documentProvider in GetInstancesOf<IClientMethods>(assemblyFilePath))
{
byte[] document = documentProvider.GetDocument(...);
}
}