programing

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

batch 2023. 5. 1. 20:40
반응형

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

C#에 로그인할 때 현재 메서드를 호출한 메서드의 이름을 어떻게 알 수 있습니까?에 대해 모두 알고 있습니다.System.Reflection.MethodBase.GetCurrentMethod()하지만 스택 추적에서 한 단계 아래로 가고 싶습니다.추적을 것을 , 는 더 합니다. 예를 들면, 택스추적구것찾싶다방습니고법을더만명지한확려했고을을는석문하분▁i▁like,다싶▁something,니습▁trace▁a▁the찾▁way▁stack▁more▁but고,방▁i▁am▁find스더▁hoping▁cleaner▁to▁explicit택▁parsing법idered've.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

Reflection [C#]을(를) 사용한 Get Calling Method에서 온 것입니다.

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는 위에서 상당히 빠르게 작동하며 대부분의 경우 성능 문제가 되지 않지만 발신자 정보는 훨씬 더 빠릅니다.1,000회 반복 샘플에서 40배 더 빠른 속도로 측정했습니다.

속도 비교가 중요한 부분인 두 가지 접근 방식을 간략하게 요약합니다.

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배 더 빠릅니다.

전체 스택이 아닌 실제로 필요한 프레임만 인스턴스화하면 아사드 씨의 코드(현재 승인된 답변)를 조금만 개선할 수 있습니다.

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

이렇게 하면 성능이 조금 더 좋아질 수 있지만, 여전히 전체 스택을 사용하여 단일 프레임을 만들어야 합니다.또한 Alex Lyman이 지적한 것과 동일한 경고를 여전히 가지고 있습니다(optimizer/native code는 결과를 손상시킬 수 있습니다).마지막으로, 당신은 확인하는 것이 좋을 것입니다.new StackFrame(1)또는.GetFrame(1)null가능성이 희박해 보일 수도 있습니다

관련 질문을 참조하십시오. 반사를 사용하여 현재 실행 중인 메서드의 이름을 찾을있습니까?

일반적으로 클래스를 사용하여 a를 얻은 다음 메서드를 사용하여 개체를 가져올 수 있습니다.그러나 이 접근 방식에는 몇 가지 주의 사항이 있습니다.

  1. 이것은 런타임 스택을 나타냅니다. 최적화는 메서드를 인라인화할 수 있으며, 스택 추적에서 해당 메서드를 수 없습니다.
  2. 네이티브 프레임을 표시하지 않으므로 네이티브 메서드에서 메서드를 호출할 가능성이 있는 경우 이 방법은 작동하지 않으며 현재 사용 가능한 방법이 없습니다.

(참고: 저는 피라스 아사드가 제공한 답변에 대해 자세히 설명하고 있습니다.)

.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 표준".

레퍼런스

  1. Microsoft - 발신자 정보(C#)
  2. 마이크로소프트 -CallerFilePathAttribute
  3. 마이크로소프트 -CallerLineNumberAttribute
  4. 마이크로소프트 -CallerMemberNameAttribute

분명히 이것은 늦은 답변이지만, 당신이 사용할 수 있다면 더 좋은 선택지가 있습니다.NET 4.5 이상:

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

현재 날짜와 시간이 인쇄되고 "이름 공간"이 표시됩니다..MethodName"로 .메서드 이름"과 ": 텍스트"로 끝납니다.
샘플 출력:

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

샘플 사용:

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

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

코드에서 호출되는 대신 코드를 수정하여 항상 위치를 파악하는 PostSharp와 같은 AOP(aspect-oriented programming)를 고려해 보십시오.

/// <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;
}

아마도 당신은 다음과 같은 것을 찾고 있을 것입니다.

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)그런 다음 호출 컨텍스트를 나타내는 고유 문자열을 전달합니다.

을 위해, 음을할거트을스▁the다▁if▁remove있▁youment,▁can/▁need습콘con▁the▁for▁caller를 제거할 수 있습니다.param선적 전에

메서드 이름 및 클래스 이름을 가져오려면 다음을 수행하십시오.

    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 Assad의 답변에 대한 추가 정보입니다.

사용한 적이 있습니다.new StackFrame(1).GetMethod().Name;의존성 주입이 있는 .net core 2.1에서 호출 방법을 '시작'으로 받고 있습니다.

로 시도했습니다.[System.Runtime.CompilerServices.CallerMemberName] string callerName = "".

호출자를 찾기 위해 람다를 사용할 수도 있습니다.

사용자가 정의한 방법이 있다고 가정합니다.

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

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

Action 유형의 매개 변수가 되도록 메서드 시그니처를 변경합니다(Func도 작동합니다).

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

람다 이름은 임의로 생성되지 않습니다.규칙은 다음과 같습니다. > <CallerMethodName>__X. 여기서 CallerMethodName은 이전 함수로 대체되고 X는 인덱스입니다.

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

우리가 MethodA를 호출할 때 Action/Func 매개변수는 호출자 메소드에 의해 생성되어야 합니다.예:

MethodA(() => {});

Method A 내부에서는 이제 위에 정의된 도우미 함수를 호출하여 호출자 메서드의 MethodInfo를 찾을 수 있습니다.

예:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

제 생각엔 충분할 것 같습니다.

언급URL : https://stackoverflow.com/questions/171970/how-can-i-find-the-method-that-called-the-current-method

반응형