我们在 Visual Studio 2008 中使用 VB.NET 技术时采用此方法...
首先,项目需要知道将“其他”dll作为嵌入式资源进行包含。在 Solution Explorer 中,将该 dll 文件作为项目文件添加(而不是作为引用)。然后,打开该文件的属性并将构建操作设置为“嵌入式资源”。建议您在项目结构中创建该 dll 文件的本地副本,而不是链接到其他位置。一旦项目包括了该 dll 文件,您就可以向该 dll 副本添加引用,以便在设计时使用其内容。
这样就确保了“其他”dll被包含在编译后的 dll 中,但它不会在需要时自动加载。这就是以下代码的作用:
Public Module Core
Private _initialized As Boolean
Public Sub EnsureInitialized()
If Not _initialized Then
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
_initialized = True
End If
End Sub
Private Function AssemblyResolve(ByVal sender As Object, ByVal e As ResolveEventArgs) As Assembly
Dim resourceFullName As String = String.Format("[CONTAINER ASSEMBLY].{0}.dll", e.Name.Split(","c)(0))
Dim thisAssembly As Assembly = Assembly.GetExecutingAssembly()
Using resource As Stream = thisAssembly.GetManifestResourceStream(resourceFullName)
If resource IsNot Nothing Then Return Assembly.Load(ToBytes(resource))
Return Nothing
End Using
End Function
Private Function ToBytes(ByVal instance As Stream) As Byte()
Dim capacity As Integer = If(instance.CanSeek, Convert.ToInt32(instance.Length), 0)
Using result As New MemoryStream(capacity)
Dim readLength As Integer
Dim buffer(4096) As Byte
Do
readLength = instance.Read(buffer, 0, buffer.Length)
result.Write(buffer, 0, readLength)
Loop While readLength > 0
Return result.ToArray()
End Using
End Function
End Module
将此模块放置在项目中的某个位置,并确保在调用dll中的任何其他代码之前调用
EnsureInitialized
方法以附加
AssemblyResolve
处理程序。
注意:您需要将[CONTAINER ASSEMBLY]替换为您的dll名称。
还要注意,上述代码是我们实际使用的简化版本,因为我们的代码包括log4net日志消息。这些日志消息对于真正的功能不是必需的,因此我删除了它们以简洁明了。
这种方法的主要警告是必须手动附加
AssemblyResolve
处理程序。即使您无法设置事情,使得
EnsureInitialized
仅在消费代码的初始化期间调用,您也可以在任何需要执行“其他”dll的自己的模块中调用
EnsureInitialized
。这使得代码变得更加微妙,因为您必须记住进行该初始化调用,但它确实允许您在需要时知道该dll将可用。
根据我的经验,有些“其他”dll在作为嵌入式资源提供时表现不佳,因此您可能需要进行一些尝试才能使其正常工作。
最后注意:我从未使用过ArcMap组件,所以您的情况可能会有所不同!
ToBytes
的定义以完成示例。 - TLS