我正在尝试编写一些代码,使我能够根据应用程序设置动态加载DLL到我的应用程序中。想法是在应用程序设置中设置要访问的数据库,然后加载相应的DLL并将其分配给我的应用程序访问接口的实例。
目前这是我的代码:
我有一个接口(ICRDataLayer),SQLServer.dll包含该接口的实现。我想加载程序集并将其分配给SQLDataSource对象。
上面的代码根本不起作用。没有抛出任何异常,甚至Msgbox也没有出现。 我本来期望至少会出现一个空的消息框,但是这也没有发生!
是否有一种方法可以确定加载的程序集是否实现了特定的接口?我尝试了下面的代码,但是似乎也没有做任何事情!
上面是每个DLL中的模块,从Vlad的C#示例转换而来。
下面是我导入DLL的代码:
使用此代码时出现以下错误: 无法将类型为“SQLServer.CRDataSource.SQLServer”的对象转换为类型“DynamicAssemblyLoading.ICRDataLayer”。 实际的DLL位于名为SQLServer的不同项目中,该项目与我的实现代码在同一解决方案中。CRDataSource是一个命名空间,而SQLServer是DLL的实际类名。SQLServer类实现了ICRDataLayer接口,因此我不明白为什么它不能转换它。这里名称是否重要,我原本认为不应该。
最终成功的代码 PluginUtility的内容:
目前这是我的代码:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim obj As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj, ICRDataLayer)
MsgBox(SQLDataSource.ModuleName & vbNewLine & SQLDataSource.ModuleDescription)
我有一个接口(ICRDataLayer),SQLServer.dll包含该接口的实现。我想加载程序集并将其分配给SQLDataSource对象。
上面的代码根本不起作用。没有抛出任何异常,甚至Msgbox也没有出现。 我本来期望至少会出现一个空的消息框,但是这也没有发生!
是否有一种方法可以确定加载的程序集是否实现了特定的接口?我尝试了下面的代码,但是似乎也没有做任何事情!
For Each loadedType As Type In ass.GetTypes
If GetType(ICRDataLayer).IsAssignableFrom(loadedType) Then
Dim obj1 As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj1, ICRDataLayer)
End If
Next
编辑:Vlad示例中的新代码:
Module CRDataLayerFactory
Sub New()
End Sub
' class name is a contract,
' should be the same for all plugins
Private Function Create() As ICRDataLayer
Return New SQLServer()
End Function
End Module
上面是每个DLL中的模块,从Vlad的C#示例转换而来。
下面是我导入DLL的代码:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim factory As Object = ass.CreateInstance("CRDataLayerFactory", True)
Dim t As Type = factory.GetType
Dim method As MethodInfo = t.GetMethod("Create")
Dim obj As Object = method.Invoke(factory, Nothing)
SQLDataSource = DirectCast(obj, ICRDataLayer)
编辑:基于Paul Kohler的代码实现
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
For Each ty As System.Type In s
If ty.Name.Contains("ICRDataLayer") Then
MsgBox(ty.Name)
plugin = DirectCast(Activator.CreateInstance(assemblyType), ICRDataLayer)
MessageBox.Show(plugin.ModuleName)
End If
Next
使用此代码时出现以下错误: 无法将类型为“SQLServer.CRDataSource.SQLServer”的对象转换为类型“DynamicAssemblyLoading.ICRDataLayer”。 实际的DLL位于名为SQLServer的不同项目中,该项目与我的实现代码在同一解决方案中。CRDataSource是一个命名空间,而SQLServer是DLL的实际类名。SQLServer类实现了ICRDataLayer接口,因此我不明白为什么它不能转换它。这里名称是否重要,我原本认为不应该。
最终成功的代码 PluginUtility的内容:
enter code here Public Shared Function GetInstances1(Of Type)(ByVal baseDir As String, ByVal searchPattern As String) As System.Type()
Dim tmpInstances As New List(Of Type)
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
Return s.ToArray()
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
End Try
End Function
加载DLL的代码:
enter code here
Dim basedir As String = "M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\"
Dim searchPattern As String = "*SQL*.dll"
Dim plugin As CRDataLayer.ICRDataLayer
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetExportedTypes
If assemblyType.GetInterface("CRDataLayer.ICRDataLayer") IsNot Nothing Then
plugin = DirectCast(Activator.CreateInstance(assemblyType), CRDataLayer.ICRDataLayer)
MessageBox.Show(plugin.ModuleDescription)
End If
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
Catch ex As Exception
MsgBox(ex.Message)
Clipboard.SetText(ex.Message)
End Try
ty.Name.Contains("ICRDataLayer")
- 请使用assemblyType.GetInterface("your namespace etc.ICRDataLayer")
来检查它是否“实现了该类型”(参见http://msdn.microsoft.com/en-us/library/tcctb9t8.aspx)。如果当前类型没有实现该接口,它将返回Nothing
。此外,异常似乎表明该接口未被实现,您是否在使用共享 DLL?需要使用相同的 DLL。PK - Paul Kohler