2013-01-04 6 views
15

Ho bisogno di trovare l'assembly in cui è stata avviata l'esecuzione del codice gestito.Ho bisogno di un'alternativa a `Assembly.GetEntryAssembly()` che non restituisce mai null

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

Questo mi sembra la strada da percorrere, ma il MSDN reference page for Assembly.GetEntryAssembly afferma che questo metodo "[c] un return null quando viene chiamato da codice non gestito."

In tal caso, vorrei sapere quale assembly è stato chiamato dal codice non gestito.

Esiste un modo affidabile per eseguire questa operazione, ad esempio uno che restituisce sempre un riferimento non nullo Assembly?

risposta

14

La migliore ho potuto pensare finora è il seguente, che dovrebbe operare in un singolo thread scenario:

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

(frammento di sopra è ottimizzato per facilità di comprensione, non per la velocità di esecuzione o memoria efficienza)

3

altro (in gran parte non testato) punto di partenza per una soluzione di lavoro potrebbe essere qualcosa di simile:.

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

Alcune incertezze:

  • Moduli e assiemi non sono la stessa cosa. ProcessModule potrebbe anche essere concettualmente diverso da Module. Il codice sopra riportato funzionerà sempre in presenza di assiemi multi-modulo (cioè multi-file), specialmente quando il punto di ingresso di un assembly non si trova nel modulo manifest?

  • È garantito che Process.MainModule restituisca sempre un riferimento non nullo?

6

Ho provato entrambi i metodi di stakx.

Method based on MainModule non funziona in alcuni casi speciali (assiemi dinamici ad esempio).

Method based on StackTrace può restituire un assembly troppo alto (o basso) nella gerarchia, come mscorlib.

Ho fatto un po 'di variante che funziona bene nei miei casi d'uso:

// 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; 

Fondamentalmente, io a piedi lo stack fino a quando ho trovato un metodo convenzionale denominato "Main" con void tipo di ritorno. Se non viene trovato alcun metodo, cerco un metodo invocato tramite reflection. Ad esempio, NUnit utilizza tale chiamata per caricare i test unitari.

Naturalmente, lo faccio solo se Assembly.GetEntryAssembly() restituisce null.

Problemi correlati