2011-02-28 48 views
11

我正試圖找到一種解決方案來「打入非公有方法」。調用保留調用堆棧的私有方法

我只想打電話RuntimeMethodInfo.InternalGetCurrentMethod(...),傳遞我自己的參數(這樣我就可以實現GetCallingMethod()),或者直接在我的日誌程序中使用RuntimeMethodInfo.InternatGetCurrentMethod(ref StackCrawlMark.LookForMyCaller)GetCurrentMethod被實現爲:

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

其中InternalGetCurrentMethod聲明:內部:-)。

我沒有問題使用反射調用方法,但是這會弄亂調用堆棧,這只是必須保留的一件事,否則就會失敗它的目的。

什麼是我保持堆棧跟蹤接近原來的(至少在允許StackCrawlMark s,這是LookForMeLookForMyCallerLookForMyCallersCaller。距離內的賠率是有一些複雜的方式來實現我想要什麼?

回答

17

如果有一件事我喜歡C#,它的動態方法

他們讓你繞過.NET創建者的每一個目標和意圖:。d

這裏有一個(線程安全的)解決方案:

(埃裏克利珀,請不要閱讀...)

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可能會將刺客機器人派往你的房子,所以我暫時不會迴應門。 – 2011-02-28 16:09:18

+1

@Justin:只要他們用C#編程,我就知道如何處理它們。 >:] – Mehrdad 2011-02-28 16:16:54

+0

太棒了...就像一個魅力!這麼簡單...因此,最後我可以記錄該方法而無需將System.Reflection.MethodBase.GetCurrentMethod()傳遞給日誌記錄方法!我肯定會嘗試在其他地方作爲反射替代品。順便說一句:對於那些閱讀解決方案:給新的DynamicMethod構造函數的方法名稱可以是任何你喜歡的。 – Edwin 2011-03-02 10:21:46