调用私有方法保留调用堆栈

时间:2011-02-28 14:13:04

标签: c# reflection methods private

我正试图找到“打破非公开方法”的解决方案。

我只想调用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:internal: - )。

使用反射调用方法没有问题,但这会弄乱调用堆栈,这只是必须要保留的一件事,否则就会失去它的目的。

将堆栈跟踪保持接近原始值的几率是多少(至少在允许的StackCrawlMark s的距离内,LookForMeLookForMyCallerLookForMyCallersCaller是否有一些复杂的方法可以达到我的目的?

1 个答案:

答案 0 :(得分:20)

如果我喜欢C#,那就是动态方法。

它们可以让您绕过.NET创建者的每一个目标和意图。 :d

这是一个(线程安全的)解决方案:

(Eric 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);
}