少し違ったアプローチをとった。私は、使用されている組み込みアセンブリを自動で初期化し、動的にロードするものを望んでいました。また、現在のAppDomainに既に存在していたアセンブリの複数のインスタンスを読み込まないようにしたいと考えました。以下のコードは、私のためにそれらのすべてを達成します。
Imports System.Reflection
Imports System.Runtime.CompilerServices
''' <summary>
''' This class initializes a special AssemblyResolve handler for assemblies embedded in the current assembly's resources. <para/>
''' To auto initialize create a variable as a New EmbeddedAssemblyResolverClass in any class using an embedded assembly.
''' </summary>
Public Class EmbeddedAssemblyResolverClass
Implements IDisposable
''' <summary>
''' Initialization flag.
''' </summary>
''' <returns>[Boolean]</returns>
Public ReadOnly Property Initialized As Boolean
''' <summary>
''' Raised when successfully initialized.
''' </summary>
Public Event Initilized()
''' <summary>
''' Raised when successfully uninitialized.
''' </summary>
Public Event Uninitilized()
Sub New()
Try
If Not Initialized Then
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ResolveAppDomainAssemblies
Initialized = True
RaiseEvent Initilized()
End If
Catch ex As Exception
'Maybe some error logging in the future.
MsgBox(ex.Message)
End Try
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ResolveAppDomainAssemblies
_Initialized = False
RaiseEvent Uninitilized()
End If
End If
disposedValue = True
End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above.
Dispose(True)
End Sub
#End Region
End Class
Public Module EmbeddedAssemblyResolverModule
''' <summary>
''' Returns a dictionary of assemblies loaded in the current AppDomain by full name as key.
''' </summary>
''' <returns>[Dictionary(Of String, Assembly)]</returns>
Public ReadOnly Property AppDomainAssemblies As Dictionary(Of String, Assembly)
Get
Return AppDomain.CurrentDomain.GetAssemblies.ToDictionary(Function(a) a.FullName)
End Get
End Property
''' <summary>
''' Method that attempts to resolve assemblies already loaded to the current AppDomain.
''' </summary>
''' <param name="sender">[Object]</param>
''' <param name="args">[ResolveEventArgs]</param>
''' <returns>[Assembly]</returns>
Public Function ResolveAppDomainAssemblies(sender As Object, args As ResolveEventArgs) As Assembly
'Return the existing assembly if it has already been loaded into the current AppDomain.
If AppDomainAssemblies.ContainsKey(args.Name) Then Return AppDomainAssemblies.Item(args.Name)
'Build the potential embedded resource name.
Dim ResourceName As String = String.Format("{0}.{1}.dll", Assembly.GetExecutingAssembly().FullName.Split(",").First, args.Name.Split(",").First)
'Attempt to load the requested assembly from the current assembly's embedded resources.
Return Assembly.GetExecutingAssembly.LoadEmbeddedAssembly(ResourceName)
End Function
''' <summary>
''' Loads an assembly from the current assembly's embedded resources.
''' </summary>
''' <param name="CurrentAssembly">[Assembly] Current assembly which contains the embedded assembly.</param>
''' <param name="EmbeddedAssemblyName">[String] Full name of the embedded assembly.</param>
''' <returns>[Assembly]</returns>
<Extension>
Public Function LoadEmbeddedAssembly(CurrentAssembly As Assembly, EmbeddedAssemblyName As String) As Assembly
'Return the existing assembly if it has already been loaded into the current AppDomain.
If AppDomainAssemblies.ContainsKey(EmbeddedAssemblyName) Then Return AppDomainAssemblies.Item(EmbeddedAssemblyName)
'Attempt to load the requested assembly from the current assembly's embedded resources.
Using Stream = CurrentAssembly.GetManifestResourceStream(EmbeddedAssemblyName)
If Stream Is Nothing Then Return Nothing
Dim RawAssembly As [Byte]() = New [Byte](Stream.Length - 1) {}
Stream.Read(RawAssembly, 0, RawAssembly.Length)
Return Assembly.Load(RawAssembly)
End Using
End Function
End Module
EmbeddedAssemblyResolverClass
は、実際のAssemblyResolveイベントハンドラの作成に使用されます。私は初期化され、初期化されていないためIDisposableをサポートし、イベントを追加することによって、いくつかの添えものを追加しましたが、希望しない場合は、それらをオフにトリミングすることができます。
残りのコードをEmbeddedAssemblyResolverModule
に作成しました。これは、アセンブリにグローバルになるように、また、LoadEmbeddedAssemblyメソッドがExtensionメソッド(モジュールでのみ作成可能)になっているためです。
残っている唯一のことは、リソース内に埋め込まれているアセンブリを使用するアプリケーション内の他のクラスにあるEmbeddedAssemblyResolverClass
を作成してインスタンス化することです。
'''' <summary>
'''' Used to auto initialize the EmbeddedAssemblyResolverClass.
'''' </summary>
Public WithEvents EAR As New EmbeddedAssemblyResolverClass
あなたが埋め込まれたリソースからメソッドをコールすると、それは最初のアセンブリがすでに現在のAppDomainにロードされている場合、それはその後、アセンブリが返されているかどうかを確認することになります。埋め込みアセンブリが読み込まれていない場合、埋め込みアセンブリが存在する場合は、組み込みアセンブリから動的に読み込まれます。このコードについての素晴らしいです
ことの一つは、それがクラスライブラリのように、エントリーポイントを持っていないアセンブリに動作することです。また、このコードを使用した組み込みアセンブリを含む組み込みアセンブリの読み込みに成功しました。
TLSは、どうもありがとうございました。あなたが提供したコードに奇妙なエラーが見つかりました。 「FormatWithは」可能System.Stringのメンバーではない、「第一」のSystem.Arrayのメンバーではない、と「ToBytes」System.IO.Streamのメンバーではありません。どのようなアイデアを私はそれらの機能を置き換えることができますか? –
申し訳ありません!私はそれをきれいにしましたが、十分には行きませんでした。私たちのコードには、標準的なメソッドに変換するのを忘れてしまった拡張メソッドがいくつかあります。私はコードを更新し、例を完成させるために 'ToBytes'の定義を追加しました。 – TLS
私の答えは、本質的に[このC#の答え(http://stackoverflow.com/a/97290/475820)の変換です。私は私の投稿後にその答えを見直した後にこれを見る。今はC#とVB版です! – TLS