[C#] 현재 메소드를 호출 한 메소드를 어떻게 찾을 수 있습니까?

C #에 로그인 할 때 현재 메서드를 호출 한 메서드의 이름을 어떻게 알 수 있습니까? 에 대해 모두 알고 System.Reflection.MethodBase.GetCurrentMethod()있지만 스택 추적에서이 단계 아래로 한 단계 이동하고 싶습니다. 스택 추적을 파싱하는 것을 고려 Assembly.GetCallingAssembly()했지만 메소드 와 같은 더 명확한 방법을 찾고 싶습니다 .



답변

이 시도:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

짧막 한 농담:

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

리플렉션 [C #]을 사용하여 호출 방법 가져 오기 입니다.


답변

C # 5에서는 호출자 정보를 사용하여 해당 정보를 얻을 수 있습니다 .

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "")
{
    Console.WriteLine(callerName + "called me.");
} 

당신은 또한 얻을 수 있습니다 [CallerFilePath][CallerLineNumber].


답변

발신자 정보 및 선택적 매개 변수를 사용할 수 있습니다.

public static string WhoseThere([CallerMemberName] string memberName = "")
{
       return memberName;
}

이 테스트는 이것을 보여줍니다 :

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}

StackTrace는 매우 빠르게 작동하지만 대부분의 경우 호출자 정보가 훨씬 빠릅니다. 1000 회 반복 샘플에서 40 배 빠르게 클럭했습니다.


답변

속도 비교가 중요한 부분 인 2 가지 방법에 대한 빠른 요약.

http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

컴파일 타임에 호출자 결정

static void Log(object message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}

스택을 사용하여 발신자 결정

static void Log(object message)
{
    // frame 1, true for source info
    StackFrame frame = new StackFrame(1, true);
    var method = frame.GetMethod();
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber();

    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}

두 가지 접근법의 비교

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms

따라서 속성을 사용하는 것이 훨씬 빠릅니다. 실제로 거의 25 배 더 빠릅니다.


답변

우리는 전체 스택이 아니라 실제로 필요한 프레임 만 인스턴스화하여 Assad의 코드 (현재 허용되는 답변)를 약간 향상시킬 수 있습니다.

new StackFrame(1).GetMethod().Name;

이 방법은 조금 더 나은 성능을 발휘할 수 있지만 모든 가능성에서 여전히 단일 프레임을 만들려면 전체 스택을 사용해야합니다. 또한 Alex Lyman이 지적한 것과 동일한 경고가 여전히 있습니다 (최적화 / 기본 코드는 결과를 손상시킬 수 있음). 마지막으로, 가능성이없는 것처럼 확인 new StackFrame(1)하거나 .GetFrame(1)리턴하지 않는지 null확인할 수 있습니다.

이 관련 질문을 참조하십시오 :
리플렉션을 사용하여 현재 실행중인 메소드의 이름을 찾을 수 있습니까?


답변

일반적으로 System.Diagnostics.StackTrace클래스를 사용 하여을 얻은 System.Diagnostics.StackFrame다음 GetMethod()메소드를 사용하여 System.Reflection.MethodBase객체 를 얻을 수 있습니다. 그러나이 방법에는 몇 가지주의 사항 이 있습니다.

  1. 런타임 스택을 나타냅니다. 최적화는 메소드를 인라인 할 수 있으며 스택 추적에서 해당 메소드를 볼 수 없습니다 .
  2. 기본 프레임 은 표시 되지 않으므로 기본 메소드에서 메소드를 호출 할 가능성이 있어도 작동 하지 않으며 실제로 사용할 수있는 방법이 없습니다.

( 참고 : Firas Assad가 제공 한 답변을 확장하고 있습니다.)


답변

.NET 4.5부터 발신자 정보 속성을 사용할 수 있습니다 .

  • CallerFilePath -함수를 호출 한 소스 파일
  • CallerLineNumber -함수를 호출 한 코드 라인;
  • CallerMemberName -함수를 호출 한 멤버

    public void WriteLine(
        [CallerFilePath] string callerFilePath = "",
        [CallerLineNumber] long callerLineNumber = 0,
        [CallerMemberName] string callerMember= "")
    {
        Debug.WriteLine(
            "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}",
            callerFilePath,
            callerLineNumber,
            callerMember);
    }

 

이 기능은 “.NET Core”및 “.NET Standard”에도 있습니다.

참고 문헌

  1. Microsoft-발신자 정보 (C #)
  2. Microsoft- CallerFilePathAttribute클래스
  3. Microsoft- CallerLineNumberAttribute클래스
  4. Microsoft- CallerMemberNameAttribute클래스