【问题标题】:Call private method retaining call stack调用私有方法保留调用栈
【发布时间】:2011-07-05 19:27:35
【问题描述】:

我正在努力寻找“闯入非公共方法”的解决方案。

我只想调用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 的声明位置:内部 :-)。

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

保持堆栈跟踪接近原始的可能性有多大(至少在允许的StackCrawlMarks 的距离内,即LookForMeLookForMyCallerLookForMyCallersCaller。有没有一些复杂的方法来实现我想要什么?

【问题讨论】:

    标签: c# reflection methods private


    【解决方案1】:

    如果我喜欢 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);
    }
    

    【讨论】:

    • 这太酷了。我必须更多地阅读动态方法。不过,Eric Lippert 可能会派刺客机器人到你家,所以我暂时不会开门。
    • @Justin:只要它们是用 C# 编程的,我就知道如何处理它们。 >:]
    • 太棒了...像魅力一样工作!如此简单......所以最后我可以在不将 System.Reflection.MethodBase.GetCurrentMethod() 传递给记录方法的情况下记录该方法!我肯定会在其他地方尝试将此作为反射替代品。顺便说一句:对于那些阅读解决方案的人:赋予新 DynamicMethod 构造函数的方法名称可以是您喜欢的任何名称。
    • 你知道关于动态生成方法/IL的好书或网址吗?很想了解更多。
    • 8 年后,它仍然派上用场。我使用它从基类构造函数中获取调用派生类构造函数的自定义属性。当然,我可以用更传统的方式解决它(直到我发现这个),但这非常符合要求!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 2016-05-14
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多