マネージコードの実行が開始されたアセンブリを見つける必要があります。
// using System.Reflection;
Assembly entryAssembly = Assembly.GetEntryAssembly();
これは進むべき道のように思えますが、 Assembly.GetEntryAssembly
のMSDNリファレンスページ は、このメソッド "[c]がアンマネージから呼び出されたときにnullを返すと述べていますコード。 "
その場合、どのアセンブリがアンマネージコードによって呼び出されたかを知りたいです。
これを行うための信頼できる方法、つまり常にnull以外のAssembly
参照を返す方法はありますか?
これまでに考えられた最善の方法は次のとおりです。これは、シングルスレッドのシナリオで機能するはずです。
// using System.Diagnostics;
// using System.Linq;
Assembly entryAssembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;
(上記のスニペットは、実行速度やメモリ効率ではなく、理解を容易にするために最適化されています。)
Stakxの両方の方法を試しました。
MainModuleに基づくメソッド 一部の特殊なケース(動的アセンブリなど)では機能しません。
StackTraceに基づくメソッド は、mscorlibのように、階層内で高すぎる(または低すぎる)アセンブリを返す可能性があります。
私は自分のユースケースでうまく機能する小さなバリアントを作成しました:
_// using System.Diagnostics;
// using System.Linq;
var methodFrames = new StackTrace().GetFrames().Select(t => t.GetMethod()).ToArray();
MethodBase entryMethod = null;
int firstInvokeMethod = 0;
for (int i = 0; i < methodFrames.Length; i++)
{
var method = methodFrames[i] as MethodInfo;
if (method == null)
continue;
if (method.IsStatic &&
method.Name == "Main" &&
(
method.ReturnType == typeof(void) ||
method.ReturnType == typeof(int) ||
method.ReturnType == typeof(Task) ||
method.ReturnType == typeof(Task<int>)
))
{
entryMethod = method;
}
else if (firstInvokeMethod == 0 &&
method.IsStatic &&
method.Name == "InvokeMethod" &&
method.DeclaringType == typeof(RuntimeMethodHandle))
{
firstInvokeMethod = i;
}
}
if (entryMethod == null)
entryMethod = firstInvokeMethod != 0 ? methodFrames[firstInvokeMethod - 1] : methodFrames.Last();
Assembly entryAssembly = entryMethod.Module.Assembly;
_
基本的に、void
またはint
の戻り値の型を持つ "Main"という名前の 従来のメソッド が見つかるまでスタックを上に移動します。そのようなメソッドが見つからない場合は、リフレクションを介して呼び出されるメソッドを探します。たとえば、NUnitはその呼び出しを使用して単体テストをロードします。
もちろん、私はAssembly.GetEntryAssembly()
がnull
を返す場合にのみそれを行います。
実用的なソリューションのもう1つの(ほとんどテストされていない)開始点は、次のようなものです。
// using System;
// using System.Diagnostics;
// using System.Linq;
ProcessModule mainModule = Process.GetCurrentProcess().MainModule;
Assembly entryAssembly = AppDomain.CurrentDomain.GetAssemblies()
.Single(Assembly => Assembly.Location == mainModule.FileName);
いくつかの不確実性が残っています:
モジュールとアセンブリは同じものではありません。 ProcessModule
はModule
とは概念的に異なる場合もあります。上記のコードは、特にアセンブリのエントリポイントがマニフェストモジュールにない場合、マルチモジュール(つまりマルチファイル)アセンブリが存在する場合に常に機能しますか?
Process.MainModule
常にnull以外の参照を返すことが保証されていますか?