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 가지 방법에 대한 빠른 요약.
컴파일 타임에 호출자 결정
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
객체 를 얻을 수 있습니다. 그러나이 방법에는 몇 가지주의 사항 이 있습니다.
- 런타임 스택을 나타냅니다. 최적화는 메소드를 인라인 할 수 있으며 스택 추적에서 해당 메소드를 볼 수 없습니다 .
- 기본 프레임 은 표시 되지 않으므로 기본 메소드에서 메소드를 호출 할 가능성이 있어도 작동 하지 않으며 실제로 사용할 수있는 방법이 없습니다.
( 참고 : 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”에도 있습니다.
참고 문헌