문제

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);

그것은 왔습니다 반사를 사용하여 통화 방법을 얻으십시오 [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 배 더 빠르게 시계를 기록했다.

전체 스택이 아닌 실제로 필요한 프레임만 인스턴스화하여 Mr 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가 제공합니다.)

속도 비교가 중요한 부분 인 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 배 더 빠릅니다.

.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. 마이크로 소프트 - CallerFilePathAttribute 수업
  3. 마이크로 소프트 - CallerLineNumberAttribute 수업
  4. 마이크로 소프트 - CallerMemberNameAttribute 수업

최적화로 인해 릴리스 코드에서는 신뢰할 수 없습니다. 또한 샌드 박스 모드 (네트워크 공유)에서 응용 프로그램을 실행하면 스택 프레임을 전혀 잡을 수 없습니다.

고려하다 측면 지향 프로그래밍 (AOP), 좋아요 포스트 쇼트, 코드에서 호출되는 대신 코드를 수정하여 코드가 항상 어디에 있는지 알고 있습니다.

/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
   string str = "";
   try
   {
      StackTrace st = new StackTrace();
      StackFrame[] frames = st.GetFrames();
      for (int i = 0; i < st.FrameCount - 1; i++)
      {
         if (frames[i].GetMethod().Name.Equals(MethodAfter))
         {
            if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
            {
               str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
               break;
            }
         }
      }
   }
   catch (Exception) { ; }
   return str;
}

분명히 이것은 늦은 답변이지만 .NET 4.5 이상을 사용할 수 있다면 더 나은 옵션이 있습니다.

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

이것은 현재 날짜와 시간을 인쇄 한 다음 "namespace.classname.methodname"을 인쇄하고 ": text"로 끝납니다.
샘플 출력 :

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

샘플 사용 :

Logger.WriteInformation<MainWindow>("MainWindow initialized");

어쩌면 당신은 다음과 같은 것을 찾고있을 것입니다.

StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name

MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name
private static MethodBase GetCallingMethod()
{
  return new StackFrame(2, false).GetMethod();
}

private static Type GetCallingType()
{
  return new StackFrame(2, false).GetMethod().DeclaringType;
}

환상적인 수업이 여기에 있습니다. http://www.csharp411.com/c-get-calling-method/

내가 사용한 또 다른 접근법은 해당 메소드에 매개 변수를 추가하는 것입니다. 예를 들어, 대신 void Foo(), 사용 void Foo(string context). 그런 다음 호출 컨텍스트를 나타내는 고유 한 문자열을 전달하십시오.

개발을 위해 발신자/컨텍스트 만 필요하면 param 배송 전에.

StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

충분할 것입니다.

보세요 .NET의 로깅 메소드 이름입니다. 생산 코드에서 사용하는 것을 조심하십시오. stackframe은 신뢰할 수 없을 수 있습니다 ...

발신자를 찾기 위해 Lambda를 사용할 수도 있습니다.

귀하가 정의한 방법이 있다고 가정합니다.

public void MethodA()
    {
        /*
         * Method code here
         */
    }

그리고 당신은 그것이 발신자라는 것을 찾고 싶습니다.

1. 메소드 서명을 변경하여 유형 액션의 매개 변수를 갖습니다 (FUNC도 작동 함).

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

2. 람다 이름은 무작위로 생성되지 않습니다. 규칙은 다음과 같습니다.>u003CCallerMethodName> __x는 CallermethodName이 이전 함수로 대체되고 X는 인덱스입니다.

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf("&gt;", 1, StringComparison.Ordinal) - 1)
              );
    }

3. Methoda를 호출하면 action/func 매개 변수를 발신자 메소드에 의해 생성해야합니다. 예시:

MethodA(() => {});

4. 내부 메소드는 이제 위에서 정의 된 도우미 기능을 호출하고 발신자 메소드의 메소드를 찾을 수 있습니다.

예시:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);

메소드 이름과 클래스 이름을 얻으려면 다음을 시도하십시오.

    public static void Call()
    {
        StackTrace stackTrace = new StackTrace();

        var methodName = stackTrace.GetFrame(1).GetMethod();
        var className = methodName.DeclaringType.Name.ToString();

        Console.WriteLine(methodName.Name + "*****" + className );
    }

Firas Assaad 답변에 대한 추가 정보.

나는 사용했다 new StackFrame(1).GetMethod().Name; 의존성 주입이있는 .NET Core 2.1에서 '시작'으로 호출 메소드를 받고 있습니다.

나는 함께 시도했다 [System.Runtime.CompilerServices.CallerMemberName] string callerName = ""그리고 그것은 올바른 호출 방법을 제공합니다

var callingMethod = new StackFrame(1, true).GetMethod();
string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top