【问题标题】:How to get the name of the class which contains the method which called the current method?如何获取包含调用当前方法的方法的类的名称?
【发布时间】:2019-01-07 10:00:22
【问题描述】:

我有一个要求,我需要知道类 (ApiController) 的名称,该类有一个方法 (GetMethod),该方法由另一个方法 (OtherMethod) 来自不同的类 (OtherClass)。

为了帮助解释这一点,我希望下面的伪代码 sn-ps 有所帮助。

ApiController.cs

public class ApiController
{
    public void GetMethod()
    {
        OtherMethod();
    }
}

OtherClass.cs

public class OtherClass()
{
    public void OtherMethod()
    {
        Console.WriteLine(/*I want to get the value 'ApiController' to print out*/)
    }
}

我的尝试:

【问题讨论】:

  • StackFrame.GetMethod() 可能对你有用。
  • 如果你知道如何获取方法,你也知道哪个类有方法。返回的信息不仅仅是一个方法的名字,它是方法的所有信息,包括类
  • new StackTrace().GetFrame(1).GetMethod().DeclaringType.FullName
  • 如果您只是使用它来打印名称,就像您的示例一样,那么它可能没问题。如果您要根据得到的答案应用任何逻辑,我会认真建议您重新审视您的设计。根据调用堆栈的确切形状神奇地改变其行为的方法非常令人困惑。 (即想象一下,如果ApiController 有某种形式的辅助类并将对OtherMethod 的调用转移到辅助类中会发生什么)
  • 请给minimal reproducible example(下次)。

标签: c#


【解决方案1】:
using System.Diagnostics;

var className = new StackFrame(1).GetMethod().DeclaringType.Name;

进入堆栈的上一层,找到方法,并从方法中获取类型。 这避免了您需要创建一个完整的 StackTrace,这很昂贵。

如果你想要完全限定的类名,你可以使用FullName

编辑:边缘案例(突出以下 cmets 中提出的问题)

  1. 如果启用了编译优化,调用方法可能是内联的,所以你可能得不到你期望的值。 (来源:Johnbot
  2. async 方法被编译到状态机中,所以同样,您可能无法得到您期望的结果。 (来源:Phil K

【讨论】:

  • 这工作谢谢!我很欣赏其他答案中的解释,尤其是@kennyzx 一个,因为它深入解释了正在发生的事情。但是,正如您所指出的,这个答案似乎是最便宜的并且得到了相同的结果,对于其他希望实现相同目标的人来说应该是一个很好的参考。
  • 这不是 100% 可靠的。如果启用了优化,GetMethod 可能会被内联并且不会显示在堆栈跟踪中。
  • 堆栈包含返回地址,一般来说,可能与调用者地址不同。见stackoverflow.com/a/6597522/1846281
【解决方案2】:

这样就可以了,

new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType.Name

StackFrame 表示调用堆栈上的一个方法,索引 1 为您提供包含当前执行方法的直接调用者的帧,在此示例中为 ApiController.GetMethod()

现在您有了框架,然后通过调用StackFrame.GetMethod() 检索该框架的MethodInfo,然后使用MethodInfoDeclaringType 属性获取定义方法的类型,这是ApiController

【讨论】:

  • 只是为了避免混淆,你行中的GetMethod()与OP的ApiController.GetMethod()无关,对吧?
  • 是的,OP 创造了一个叫做 GetMethod() 的方法,而 StackFrame 也有这个方法只是一个巧合。
【解决方案3】:

您可以通过以下代码实现此目的

首先你需要添加命名空间using System.Diagnostics;

public class OtherClass
{
    public void OtherMethod()
    {
        StackTrace stackTrace = new StackTrace();

        string callerClassName = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
        string callerClassNameWithNamespace = stackTrace.GetFrame(1).GetMethod().DeclaringType.FullName;

        Console.WriteLine("This is the only name of your class:" + callerClassName);
        Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
    }
}

stackTrace 的实例取决于您的实现环境。你可以在本地或全局定义它

您可以在不创建StackTrace 实例的情况下使用以下方法

public class OtherClass
{
    public void OtherMethod()
    {
        string callerClassName = new StackFrame(1).GetMethod().DeclaringType.Name;
        string callerClassNameWithNamespace = new StackFrame(1).GetMethod().DeclaringType.FullName;

        Console.WriteLine("This is the only name of your class:" + callerClassName);
        Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
    }
}

试试这个可能对你有帮助

【讨论】:

    【解决方案4】:

    为什么不简单地将名称作为构造函数参数传递?这不会隐藏依赖关系,不像StackFrame/StackTrace

    例如:

    public class ApiController
    {
        private readonly OtherClass _otherClass = new OtherClass(nameof(ApiController));
    
        public void GetMethod()
        {
            _otherClass.OtherMethod();
        }
    }
    
    public class OtherClass
    {
        private readonly string _controllerName;
    
        public OtherClass(string controllerName)
        {
            _controllerName = controllerName;
        }
    
        public void OtherMethod()
        {
            Console.WriteLine(_controllerName);
        }
    }
    

    【讨论】:

    • 这也是一个可行的解决方案,但我想看看如何在不将名称作为参数传递的情况下完成。
    猜你喜欢
    • 1970-01-01
    • 2011-11-25
    • 2011-01-04
    • 2016-03-13
    • 2015-02-22
    • 2016-11-01
    • 2010-10-01
    • 1970-01-01
    • 2011-07-03
    相关资源
    最近更新 更多