Как получить имя класса, содержащего метод, который вызвал текущий метод?

У меня есть требование, когда мне нужно знать имя класса (ApiController), у которого есть метод (GetMethod), который вызывается другим методом (OtherMethod) из другого класса (OtherClass).

Чтобы помочь объяснить это, я надеюсь, что ниже описаны фрагменты псевдокода.

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*/)
    }
}

Что я пробовал:

  • Я посмотрел, как найти метод, называемый текущим методом? и ответы получат мне метод вызова (OtherMethod), но не класс (ApiController), который имеет этот метод
  • Я попробовал [CallerMemberName] и использовал свойства StackTrace но это не StackTrace мне имя класса метода

Ответы

Ответ 1

using System.Diagnostics;

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

Переход на предыдущий уровень стека, поиск метода и получение типа из метода. Это позволяет избежать необходимости создания полного StackTrace, что дорого.

Вы можете использовать FullName если хотите получить полное имя класса.

Изменение: случайные случаи (чтобы выделить проблемы, поднятые в комментариях ниже)

  1. Если оптимизация компиляции включена, метод вызова может быть встроен, поэтому вы можете не получить ожидаемое значение. (Кредит: Джонбот)
  2. async методы скомпилируются в конечный автомат, так что опять же вы не можете получить то, что ожидаете. (Кредит: Фил К)

Ответ 2

Так что это можно сделать так,

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

StackFrame представляет собой метод в стеке вызовов, индекс 1 дает вам фрейм, который содержит непосредственный вызывающий ApiController.GetMethod() текущего выполняемого метода, который является ApiController.GetMethod() в этом примере.

Сейчас у вас есть кадр, то вы извлечь MethodInfo из этого кадра, вызвав StackFrame.GetMethod(), а затем использовать DeclaringType свойство MethodInfo получить тип, в котором определен метод, который ApiController.

Ответ 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);
    }
}