Я пытаюсь написать некоторый код, который позволит мне динамически загружать DLL в мое приложение, в зависимости от настроек приложения. Идея состоит в том, что база данных, к которой осуществляется доступ, задается в настройках приложения, а затем она загружает соответствующую DLL и назначает ее экземпляру интерфейса для доступа моего приложения.
Это мой код на данный момент:
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
РЕДАКТИРОВАТЬ: Новый код из примеров Влада:
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, преобразованный из примера Влада 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)
РЕДАКТИРОВАТЬ: Реализация на основе кода Пола Колера
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