2013-01-04 4 views
15

관리되는 코드 실행이 시작된 어셈블리를 찾아야합니다.null을 반환하지 않는 'Assembly.GetEntryAssembly()'대안이 필요합니다.

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

이 길을 가야하는 것처럼 보이지만 MSDN reference page for Assembly.GetEntryAssembly는 주장이이 방법 "[C] 관리되지 않는 코드에서라는 경우는 null."

이 경우, 어떤 어셈블리가 관리되지 않는 코드에 의해 호출되었는지 알고 싶습니다.

신뢰할 수있는 방법, 즉 항상 null이 아닌 Assembly 참조를 반환하는 방법이 있습니까?

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

(위의 미리보기가없는 실행 속도 나 메모리에 대한 이해의 용이성을 위해 최적화되어 있습니다 :

답변

14

지금까지 생각할 수있는 최선은 단일 스레드 시나리오에서 작동해야 다음이다 효율성)

3

이 작업 솔루션에 대한 또 다른 (대부분 검증되지 않은) 시작 지점이 같을 수 있습니다. 일부 불확실성이 남아

// 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이 아닌 참조를 반환하도록 보장됩니까?

6

나는 stakx의 두 가지 방법을 시도했다.

Method based on MainModule은 일부 특수한 경우 (예 : 동적 어셈블리)에서 작동하지 않습니다.

Method based on StackTrace은 mscorlib와 같이 계층 구조에서 너무 높거나 낮은 어셈블리를 반환 할 수 있습니다. 내가 void 반환 형식으로 "메인"라는 종래의 방법을 찾을 때까지

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

는 기본적으로, 최대 스택을 걸어 :

나는 내 사용 사례에서 잘 작동 약간의 변형을했다. 그런 메소드가 발견되지 않으면 리플렉션을 통해 호출 된 메소드를 찾습니다. 예를 들어, NUnit은 호출을 사용하여 단위 테스트를로드합니다.

물론 Assembly.GetEntryAssembly()null 인 경우에만 해당 작업을 수행합니다.