【问题标题】:Retrieving the calling method name from within a method [duplicate]从方法中检索调用方法名称[重复]
【发布时间】:2010-10-11 14:01:42
【问题描述】:

我在一个对象中有一个方法,该方法从对象中的多个位置调用。有没有一种快速简便的方法来获取调用这个流行方法的方法的名称。

伪代码示例:

public Main()
{
     PopularMethod();
}

public ButtonClick(object sender, EventArgs e)
{
     PopularMethod();
}

public Button2Click(object sender, EventArgs e)
{
     PopularMethod();
}

public void PopularMethod()
{
     //Get calling method name
}

PopularMethod() 内,如果Main 是从Main 调用的,我想查看它的值...如果PopularMethod()ButtonClick 调用,我想查看“ButtonClick

我正在查看System.Reflection.MethodBase.GetCurrentMethod(),但这不会让我获得调用方法。我查看了 StackTrace 类,但我真的不喜欢每次调用该方法时都运行整个堆栈跟踪。

【问题讨论】:

    标签: c# reflection methods calling-convention


    【解决方案1】:

    我认为您确实需要使用 StackTrace 类,然后在下一帧使用 StackFrame.GetMethod()

    不过,使用Reflection 似乎是一件奇怪的事情。如果您正在定义PopularMethod,则无法定义参数或其他东西来传递您真正想要的信息。 (或者放在基类或其他东西上......)

    【讨论】:

      【解决方案2】:

      我经常发现自己想要这样做,但总是最终重构我的系统设计,所以我没有得到这种“摇尾巴”的反模式。结果始终是更强大的架构。

      【讨论】:

        【解决方案3】:

        在 .NET 4.5 / C# 5 中,这很简单:

        public void PopularMethod([CallerMemberName] string caller = null)
        {
             // look at caller
        }
        

        编译器会自动添加调用者的名字;所以:

        void Foo() {
            PopularMethod();
        }
        

        将传入"Foo"

        【讨论】:

        • 此解决方案的性能后果是什么?
        • @Feckmore none :编译器在编译期间将其添加为文字。它比查看 StackTrace 等任何东西都要快得多。基本上它被编译为 PopularMethod("CurrentMethodName")
        • 我收到一条错误消息,提示找不到 CallerMemberName。 VS Express C# 2010
        • @user396483 您需要以 .NET 4.5 或更高版本为目标才能使属性存在(尽管您可以自己定义),并且您需要使用 C# 5 才能以所需的方式工作. VS Express 2013 可用且免费
        【解决方案4】:

        只需传入一个参数

        public void PopularMethod(object sender)
        {
        
        }
        

        IMO:如果它对事件来说足够好,那么它应该足够好。

        【讨论】:

        • Sruly - 是的,这绝对是一个选择,我试图在不改变方法调用的情况下做到这一点。这将是我最后的选择。
        • 除非您将其公开为公共 API,否则如果您可以这样做,为什么还要麻烦并使用反射呢?记住亲吻
        • 这是最好的答案,不要使用反射或其他东西,通过参数识别调用者。
        • 如果您正在寻找命名空间/程序集信息之类的信息,则传递类型可能是更好的选择,因为调用可能来自静态方法。
        • 我为许多系统编写过代码。开发人员通常希望跟踪正在编写日志条目的方法。如果日志代码需要手动传递方法名,这就需要开发者在每次调用日志方法时都将方法名作为文本输入。现在在程序的许多不同部分使用相同的日志记录方法,看看几年内与许多开发人员一起添加、删除和重命名方法会发生什么。自动传递调用者的方法名将极大地简化开发和调试。
        【解决方案5】:

        这其实很简单。

        public void PopularMethod()
        {
            var currentMethod = System.Reflection.MethodInfo
                .GetCurrentMethod(); // as MethodBase
        }
        

        但是要小心,我有点怀疑内联方法是否有任何效果。您可以这样做以确保 JIT 编译器不会妨碍您。

        [System.Runtime.CompilerServices.MethodImpl(
         System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        public void PopularMethod()
        {
            var currentMethod = System.Reflection.MethodInfo
                .GetCurrentMethod();
        }
        

        获取调用方法:

        [System.Runtime.CompilerServices.MethodImpl(
         System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        public void PopularMethod()
        {
            // 1 == skip frames, false = no file info
            var callingMethod = new System.Diagnostics.StackTrace(1, false)
                 .GetFrame(0).GetMethod();
        }
        

        【讨论】:

        • John Leidgren - 这会让我得到“PopularMethod”这个名字,但我想要名为 PopularMethod 的方法的名称。
        • 对,那么堆栈跟踪就是您所需要的。我看错了你的问题。
        • 只用 .GetFrame(1) 代替吧?
        • +1 表示MethodInlining.NoInlining。顺便说一句,StackTrace .ctor 调用上的 false 是多余的,不是吗?
        • 如果我没有明确要求文件信息,我相信它确实表现出稍微更好的性能。说实话,这可能没关系,我这样做的主要原因是因为我不需要文件信息。
        【解决方案6】:

        虽然您可以最明确地跟踪堆栈并以这种方式计算出来,但我会敦促您重新考虑您的设计。如果您的方法需要了解某种“状态”,我会说只需创建一个枚举或其他东西,并将其作为您的 PopularMethod() 的参数。类似的东西。根据您发布的内容,跟踪堆栈将是 IMO 过度杀伤力。

        【讨论】:

          【解决方案7】:

          我认为不跟踪堆栈就无法完成。但是,这样做相当简单:

          StackTrace stackTrace = new StackTrace();
          MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
          Console.WriteLine(methodBase.Name); // e.g.
          

          但是,我认为你真的必须停下来问问自己这是否有必要。

          【讨论】:

          • System.Diagnostics 是 StackTrace 的命名空间,System.Reflection 是 MethodBase 的命名空间。
          • Jason - 谢谢,我不确定“StackTrace”方法的资源密集程度如何,但这确实让我得到了我想要的东西。这对我来说只是一个调试代码块,不会投入生产。再次感谢您的帮助!
          • @Scott Vercuski - 这是一项非常昂贵的操作,如果有任何方法可以避免这种情况,你真的应该这样做。它比抛出异常更糟糕,这很糟糕。能做固然好,但不能乱用。
          • @John Leidegren - 绝对......这不会进入生产代码,我们只是在做一些大规模的 QA 测试并发生一些奇怪的事情,这只是为了帮助找出问题所在走火入魔。谢谢!
          猜你喜欢
          • 2012-11-28
          • 1970-01-01
          • 1970-01-01
          • 2014-07-07
          • 1970-01-01
          • 1970-01-01
          • 2012-12-10
          • 2016-03-31
          相关资源
          最近更新 更多