[.net] 리플렉션을 사용하여 현재 실행중인 메소드의 이름을 찾을 수 있습니까?

제목처럼 : 리플렉션은 현재 실행중인 메소드의 이름을 알려줍니다.

나는 Heisenberg 문제 때문에 추측하지 않는 경향이 있습니다. 현재 메소드를 변경하지 않고 현재 메소드를 알려주는 메소드를 어떻게 호출합니까? 그러나 누군가가 나를 잘못 증명할 수 있기를 바랍니다.

최신 정보:

  • 2 부 : 속성의 코드 내부를 살펴볼 수 있습니까?
  • 3 부 : 성능은 어떻습니까?

최종 결과
MethodBase.GetCurrentMethod ()에 대해 배웠습니다. 또한 스택 추적을 만들 수있을뿐만 아니라 원하는 경우 필요한 정확한 프레임 만 만들 수 있다는 것도 알게되었습니다.

속성 내에서 이것을 사용하려면 .Substring (4)를 사용하여 ‘set_’또는 ‘get_’을 제거하십시오.



답변

.NET 4.5 부터는 [CallerMemberName]을 사용할 수도 있습니다 .

예 : 속성 설정 기 (2 부 답변) :

    protected void SetProperty<T>(T value, [CallerMemberName] string property = null)
    {
        this.propertyValues[property] = value;
        OnPropertyChanged(property);
    }

    public string SomeProperty
    {
        set { SetProperty(value); }
    }

컴파일러는 호출 사이트에서 일치하는 문자열 리터럴을 제공하므로 기본적으로 성능 오버 헤드가 없습니다.


답변

async방법이 아닌 경우 사용할 수 있습니다

System.Reflection.MethodBase.GetCurrentMethod().Name;

https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.getcurrentmethod

async메소드의 경우 “MoveNext”가 리턴 됨을 기억하십시오 .


답변

Lex가 제공 한 스 니펫은 약간 길어서 다른 사람이 정확히 동일한 기술을 사용하지 않았기 때문에 중요한 부분을 지적하고 있습니다.

string MethodName = new StackFrame(0).GetMethod().Name;

이것은 동일한 결과를 MethodBase.GetCurrentMethod (). Name 기술에 반환해야 하지만 이전 방법에 대해 색인 1을 사용하여 자체 메소드로 한 번 구현 하고 여러 가지 다른 속성에서 호출 할 수 있기 때문에 여전히 주목할 가치가 있습니다. 또한 전체 스택 추적 대신 하나의 프레임 만 반환합니다.

private string GetPropertyName()
{  //.SubString(4) strips the property prefix (get|set) from the name
    return new StackFrame(1).GetMethod().Name.Substring(4);
}

그것은 하나의 라이너이기도합니다.)


답변

빈 콘솔 프로그램의 Main 메소드 내에서 이것을 시도하십시오.

MethodBase method = MethodBase.GetCurrentMethod();
Console.WriteLine(method.Name);

콘솔 출력 :
Main


답변

네 물론 이죠

객체를 조작하려면 실제로 다음과 같은 함수를 사용하십시오.

public static T CreateWrapper<T>(Exception innerException, params object[] parameterValues) where T : Exception, new()
{
    if (parameterValues == null)
    {
        parameterValues = new object[0];
    }

    Exception exception   = null;
    StringBuilder builder = new StringBuilder();
    MethodBase method     = new StackFrame(2).GetMethod();
    ParameterInfo[] parameters = method.GetParameters();
    builder.AppendFormat(CultureInfo.InvariantCulture, ExceptionFormat, new object[] { method.DeclaringType.Name, method.Name });
    if ((parameters.Length > 0) || (parameterValues.Length > 0))
    {
        builder.Append(GetParameterList(parameters, parameterValues));
    }

    exception = (Exception)Activator.CreateInstance(typeof(T), new object[] { builder.ToString(), innerException });
    return (T)exception;
}

이 줄 :

MethodBase method     = new StackFrame(2).GetMethod();

스택 프레임을 걸어 호출 메소드를 찾은 다음 리플렉션을 사용하여 일반 오류보고 기능을 위해 전달 된 매개 변수 정보 값을 얻습니다. 현재 방법을 얻으려면 현재 스택 프레임 (1)을 대신 사용하십시오.

다른 사람들이 현재 메소드 이름에 대해 말했듯이 다음을 사용할 수도 있습니다.

MethodBase.GetCurrentMethod()

그 방법을 내부적으로 보면 단순히 StackCrawlMark를 생성하기 때문에 스택을 걷는 것이 좋습니다. 스택을 해결하는 것이 나에게 더 분명해 보입니다.

4.5 이후에는 메소드 매개 변수의 일부로 [CallerMemberNameAttribute]를 사용하여 메소드 이름의 문자열을 얻을 수 있습니다. 이는 일부 시나리오에서 도움이 될 수 있습니다 (그러나 실제로는 위의 예에서)

public void Foo ([CallerMemberName] string methodName = null)

이것은 주로 이벤트 코드를 통해 문자열이 흩어진 INotifyPropertyChanged 지원을위한 솔루션 인 것 같습니다.


답변

LinqPad에서 임의의 타이밍 구성 을 사용하여 메소드 이름을 얻는 방법 비교 :

암호

void Main()
{
    // from http://blogs.msdn.com/b/webdevelopertips/archive/2009/06/23/tip-83-did-you-know-you-can-get-the-name-of-the-calling-method-from-the-stack-using-reflection.aspx
    // and /programming/2652460/c-sharp-how-to-get-the-name-of-the-current-method-from-code

    var fn = new methods();

    fn.reflection().Dump("reflection");
    fn.stacktrace().Dump("stacktrace");
    fn.inlineconstant().Dump("inlineconstant");
    fn.constant().Dump("constant");
    fn.expr().Dump("expr");
    fn.exprmember().Dump("exprmember");
    fn.callermember().Dump("callermember");

    new Perf {
        { "reflection", n => fn.reflection() },
        { "stacktrace", n => fn.stacktrace() },
        { "inlineconstant", n => fn.inlineconstant() },
        { "constant", n => fn.constant() },
        { "expr", n => fn.expr() },
        { "exprmember", n => fn.exprmember() },
        { "callermember", n => fn.callermember() },
    }.Vs("Method name retrieval");
}

// Define other methods and classes here
class methods {
    public string reflection() {
        return System.Reflection.MethodBase.GetCurrentMethod().Name;
    }
    public string stacktrace() {
        return new StackTrace().GetFrame(0).GetMethod().Name;
    }
    public string inlineconstant() {
        return "inlineconstant";
    }
    const string CONSTANT_NAME = "constant";
    public string constant() {
        return CONSTANT_NAME;
    }
    public string expr() {
        Expression<Func<methods, string>> ex = e => e.expr();
        return ex.ToString();
    }
    public string exprmember() {
        return expressionName<methods,string>(e => e.exprmember);
    }
    protected string expressionName<T,P>(Expression<Func<T,Func<P>>> action) {
        // https://stackoverflow.com/a/9015598/1037948
        return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name;
    }
    public string callermember([CallerMemberName]string name = null) {
        return name;
    }
}

결과

반사
반사

스택
트레이스

인라인
상수 인라인 상수

상수
상수

expr
e => e.expr ()

exprmember
exprmember

발신자
메인

Method name retrieval: (reflection) vs (stacktrace) vs (inlineconstant) vs (constant) vs (expr) vs (exprmember) vs (callermember)

 154673 ticks elapsed ( 15.4673 ms) - reflection
2588601 ticks elapsed (258.8601 ms) - stacktrace
   1985 ticks elapsed (  0.1985 ms) - inlineconstant
   1385 ticks elapsed (  0.1385 ms) - constant
1366706 ticks elapsed (136.6706 ms) - expr
 775160 ticks elapsed ( 77.516  ms) - exprmember
   2073 ticks elapsed (  0.2073 ms) - callermember


>> winner: constant

있습니다 exprcallermember방법은 아주 “오른쪽”아니다. 여기 에서 리플렉션이 스택 트레이스보다 15 배 빠르다는 관련 주석 이 반복되는 것을 볼 수 있습니다 .


답변

편집 : MethodBase는 아마도 전체 호출 스택과 달리 현재 사용중인 메소드를 얻는 더 좋은 방법 일 것입니다. 그러나 여전히 인라인에 대해 걱정하고 있습니다.

메소드 내에서 StackTrace를 사용할 수 있습니다.

StackTrace st = new StackTrace(true);

그리고 프레임을 살펴보십시오.

// The first frame will be the method you want (However, see caution below)
st.GetFrames();

그러나 메소드가 인라인 된 경우 사용자가 생각하는 메소드 내부에 있지 않을 것입니다. 인라인을 방지하기 위해 속성을 사용할 수 있습니다.

[MethodImpl(MethodImplOptions.NoInlining)]