リンクした回答のコードには、下に向かって線があります。
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName)
Reflection.Load
代わりに呼び出して完全修飾アセンブリ名を渡すと、GAC(および、アセンブリがGACにない場合は、他のいくつかの場所)からアセンブリをロードしようとします。
let asm =
Assembly.Load "SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3"
完全修飾アセンブリ名がわからない場合は、アセンブリの単純な名前でを作成する必要があります。次に、の代わりに取るオーバーロードをAssemblyName
呼び出します。Reflection.Load
AssemblyName
string
let asmName = AssemblyName "Your.Assembly.Name"
let asm = Assembly.Load asmName
ロードするアセンブリを知る限り、プログラムでそれを決定する簡単な方法はないと思います。私が今考えることができる唯一の2つの解決策:
- 与えられているコード(文字列として)についてある程度の知識がある場合は、でそれを解析し
FSharpCodeProvider
、どの名前空間/モジュールが開かれ、どのタイプが使用されているかを調べることができます。特定の名前空間またはタイプが使用されているかどうか(つまり、コードをコンパイルするときにアセンブリ参照を含める必要があるかどうか)を確認する場合は、名前空間のマップ(.fsx
コンパイルを実行しているユーザー)を作成できます。および/または名前をアセンブリ名に入力し、それを使用して適切なアセンブリを参照します。
- 半文書化されたFusionAPIを使用してGACにインストールされているすべてのアセンブリを列挙し、Reflectionを使用して各アセンブリを調べ、必要なアセンブリかどうかを判断することで、GACを「ブルートフォース」で検索できます。これは非常に遅い可能性が高いので、絶対に避けたいと思います。このルートを使用する場合は、このメソッドを使用してアセンブリをロードする必要もあります。
Assembly.ReflectionOnlyLoad
これにより、アセンブリの調査が終了した後にアセンブリをアンロードできます。通常のReflectionを使用している場合、アセンブリをアンロードできず、プログラムがOutOfMemoryException
または同様のものでクラッシュする可能性があります。
編集:AppDomain.AssemblyResolveイベントのハンドラーが自動的にインストールされるため、単純な名前でのアセンブリの読み込みは成功しfsi
、通常のF#コードでは成功しないことがわかりました。このイベントは、アセンブリを読み込もうとしたときにCLRによってトリガーされ、解決できません。このイベントは、アセンブリを「手動で」解決したり、アセンブリを動的に生成して返す方法を提供します。fsi
F#プロジェクトでコードを実行しようとしたときに発生したものを見るFileNotFoundException
と、例外のFusionLogプロパティに次のようなものが表示されます。
=== Pre-bind state information ===
LOG: User = Jack-Laptop\Jack
LOG: DisplayName = System
(Partial)
WRN: Partial binding information was supplied for an assembly:
WRN: Assembly Name: System | Domain ID: 1
WRN: A partial bind occurs when only part of the assembly display name is provided.
WRN: This might result in the binder loading an incorrect assembly.
WRN: It is recommended to provide a fully specified textual identity for the assembly,
WRN: that consists of the simple name, version, culture, and public key token.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue.
LOG: Appbase = file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : StackOverflow1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System.DLL.
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System/System.DLL.
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System.EXE.
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System/System.EXE.
そのログの下部を見ると、CLRがアセンブリをあきらめる前に検索した場所がわかります。
AppDomain.AssemblyResolveハンドラーを使用してアセンブリを手動で解決する方法を理解するための簡単なハンドラーを次に示します。(注:アセンブリをロードしようとするコードの前にハンドラーを追加する必要があります!)
System.AppDomain.CurrentDomain.add_AssemblyResolve (
System.ResolveEventHandler (fun _ args ->
let resolvedAssembly =
System.AppDomain.CurrentDomain.GetAssemblies ()
|> Array.tryFind (fun loadedAssembly ->
// If this assembly has the same name as the one we're looking for,
// assume it's correct and load it. NOTE : It may not be the _exact_
// assembly we're looking for -- then you'll need to adjust the critera below.
args.Name = loadedAssembly.FullName
|| args.Name = loadedAssembly.GetName().Name)
// Return null if the assembly couldn't be resolved.
defaultArg resolvedAssembly null))
そのコードを新しいF#コンソールプロジェクトに追加し、続いAssemblyName
てAssembly.Loadで使用するコードを追加すると、System
アセンブリはF#プロジェクトでデフォルトで参照され、実行時に読み込まれるため、アセンブリを読み込むことができます。事業。を解決しようとするSystem.Drawing
と、カスタムイベントハンドラーがアセンブリを見つけることができないため、失敗します。明らかに、より複雑なアセンブリ解決ロジックが必要な場合は、アプリケーションにとって意味のある方法でイベントハンドラーに組み込む必要があります。
最後に、例外メッセージで言及されているMSDNホワイトペーパーへのリンクがあります:アセンブリロードのベストプラクティス。行き詰まり、必要なアセンブリを解決する方法がわからない場合は、一読する価値があります。