2011-02-28 10 views
11

'비공개 방법으로 침입'할 해결책을 찾고 있습니다.호출 스택을 보유한 개인 메서드 호출

RuntimeMethodInfo.InternalGetCurrentMethod(...)을 호출하고 내 자신의 매개 변수를 전달 (GetCallingMethod()을 구현할 수 있음)하거나 직접 로깅 루틴에 RuntimeMethodInfo.InternatGetCurrentMethod(ref StackCrawlMark.LookForMyCaller)을 사용하고 싶습니다. InternalGetCurrentMethod 선언

[MethodImpl(MethodImplOptions.NoInlining)] 
public static MethodBase GetCurrentMethod() 
{  
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;  
    return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller); 
} 

: 내부 :-) GetCurrentMethod는 다음과 같이 구현된다.

리플렉션을 사용하여 메서드를 호출하는 데 아무런 문제가 없지만이 메서드는 호출 스택을 망칠뿐입니다.이 메서드는 보존해야하는 한 가지 방법입니다. 그렇지 않으면 그 목적을 상실합니다.

적어도 LookForMe, LookForMyCallerLookForMyCallersCaller 있습니다. 허용 StackCrawlMark의의 거리 내 (원본에 가까운 스택 트레이스를 유지 나의 확률은 내가 원하는 것을 달성하기 위해 몇 가지 복잡한 방법이 있습니까?

답변

17
나는 C#을 사랑에 대해서 한 가지가 있다면

, 그것은 동적 방법입니다

그들은 당신이 .NET 제작자의 모든 목표와 의도를 무시하자.. D

을 여기에 (스레드 안전) 솔루션입니다 :

(에릭 Lippert의이 읽을하지 마십시오 ...)

enum MyStackCrawlMark { LookForMe, LookForMyCaller, LookForMyCallersCaller, LookForThread } 
delegate MethodBase MyGetCurrentMethodDelegate(ref MyStackCrawlMark mark); 
static MyGetCurrentMethodDelegate dynamicMethod = null; 

static MethodBase MyGetCurrentMethod(ref MyStackCrawlMark mark) 
{ 
    if (dynamicMethod == null) 
    { 
     var m = new DynamicMethod("GetCurrentMethod", 
      typeof(MethodBase), 
      new Type[] { typeof(MyStackCrawlMark).MakeByRefType() }, 
      true //Ignore all privilege checks :D 
     ); 
     var gen = m.GetILGenerator(); 
     gen.Emit(OpCodes.Ldarg_0); //NO type checking here! 
     gen.Emit(OpCodes.Call, 
      Type.GetType("System.Reflection.RuntimeMethodInfo", true) 
       .GetMethod("InternalGetCurrentMethod", 
        BindingFlags.Static | BindingFlags.NonPublic)); 
     gen.Emit(OpCodes.Ret); 
     Interlocked.CompareExchange(ref dynamicMethod, 
      (MyGetCurrentMethodDelegate)m.CreateDelegate(
       typeof(MyGetCurrentMethodDelegate)), null); 
    } 
    return dynamicMethod(ref mark); 
} 
[MethodImpl(MethodImplOptions.NoInlining)] 
static void Test() 
{ 
    var mark = MyStackCrawlMark.LookForMe; //"Me" is Test's _caller_, NOT Test 
    var method = MyGetCurrentMethod(ref mark); 
    Console.WriteLine(method.Name); 
} 
+0

이 슈퍼 멋지다. 나는 동적 인 방법을 더 읽어야한다. Eric Lippert는 자객 용 드로이드를 집으로 파견하고 있을지 모르니 잠시 문을 닫지 않을 것입니다. –

+1

@ Justin : C#으로 프로그래밍되는 한, 어떻게 다루는 지 알게 될 것입니다. > :] – Mehrdad

+0

굉장 ... 매력처럼 작동합니다! 그리고 그렇게 쉬운 ... 그래서 마침내 System.Reflection.MethodBase.GetCurrentMethod()를 로깅 메서드에 전달하지 않고 메서드를 기록 할 수 있습니다! 나는 이것을 다른 장소에서도 반성의 대용으로 확실히 시도 할 것이다. Btw : 솔루션을 읽는 사람들을 위해 : 새로운 DynamicMethod 생성자에 제공된 메서드 이름은 원하는 것일 수 있습니다. – Edwin