2013-01-04 12 views
15

Potrzebuję znaleźć zespół, w którym rozpoczęło się uruchamianie zarządzanego kodu.Potrzebuję alternatywy dla `Assembly.GetEntryAssembly()`, która nigdy nie zwróci wartości null

// using System.Reflection; 
Assembly entryAssembly = Assembly.GetEntryAssembly(); 

Wydaje się to do zrobienia, ale MSDN reference page for Assembly.GetEntryAssembly stwierdza, że ​​ta metoda „[c] zerowy powrotny gdy wywoływana z kodem niezarządzanym”.

W takim przypadku chciałbym wiedzieć, który zestaw został wywołany przez niezarządzanego kodu.

Czy istnieje niezawodny sposób robienia tego, tzn. Taki, który zawsze zwraca niezerowy numer referencyjny Assembly?

Odpowiedz

14

Najlepszym mogę myśleć o tak daleko jest następujące, które powinny pracować w jednowątkowym scenariusz:

// using System.Diagnostics; 
// using System.Linq; 
Assembly entryAssembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly; 

(Powyższy fragment jest zoptymalizowany pod kątem łatwości zrozumienia, nie dla szybkości wykonania lub pamięci sprawność)

3

Innym (w dużej mierze niesprawdzone) punktem wyjścia do roztworu roboczego może być coś takiego:.

// using System; 
// using System.Diagnostics; 
// using System.Linq; 
ProcessModule mainModule = Process.GetCurrentProcess().MainModule; 
Assembly entryAssembly = AppDomain.CurrentDomain.GetAssemblies() 
         .Single(assembly => assembly.Location == mainModule.FileName); 

Niektóre niepewności pozostają:

  • Moduły i złożenia to nie to samo. ProcessModule może nawet różnić się pod względem koncepcyjnym od Module. Czy powyższy kod zawsze działałby w obecności zespołów wielomodułowych (tzn. Wielu plików), zwłaszcza gdy punkt wejścia zespołu nie znajduje się w module manifestu?

  • Czy Process.MainModule jest gwarantowane, że zawsze zwraca wartość inną niż null?

6

Próbowałem obu metod stakx.

Method based on MainModule nie działa w niektórych szczególnych przypadkach (na przykład dynamiczne złożenia).

Method based on StackTrace może przywrócić w hierarchii zbyt wysoki (lub niski) zbiór, taki jak mscorlib.

Zrobiłem trochę wariant, który działa dobrze w moich przypadkach zastosowanie:

// 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.Name == "Main" && method.ReturnType == typeof(void)) 
     entryMethod = method; 
    else if (firstInvokeMethod == 0 && method.Name == "InvokeMethod" && method.IsStatic && method.DeclaringType == typeof(RuntimeMethodHandle)) 
     firstInvokeMethod = i; 
} 

if (entryMethod == null) 
    entryMethod = firstInvokeMethod != 0 ? methodFrames[firstInvokeMethod - 1] : methodFrames.Last(); 

Assembly entryAssembly = entryMethod.Module.Assembly; 

Zasadniczo chodzić stosu aż znajdę konwencjonalną metodę o nazwie „main” z void typ zwracany. Jeśli taka metoda nie zostanie znaleziona, szukam metody wywoływanej przez odbicie. Na przykład NUnit używa tego wywołania do załadowania testów jednostkowych.

Oczywiście, robię to tylko wtedy, gdy Assembly.GetEntryAssembly() zwraca null.

Powiązane problemy