리플렉션을 사용하여 현재 실행 중인 메서드의 이름을 찾을 수 있나요?

StackOverflow https://stackoverflow.com/questions/44153

  •  09-06-2019
  •  | 
  •  

문제

제목에서 알 수 있듯이:리플렉션을 통해 현재 실행 중인 메서드의 이름을 알 수 있습니다.

나는 하이젠베르크 문제 때문에 그렇지 않다고 추측하고 싶습니다.현재 메서드가 무엇인지 변경하지 않고 현재 메서드를 알려주는 메서드를 어떻게 호출합니까?하지만 누군가가 내가 틀렸다는 것을 증명할 수 있기를 바랍니다.

업데이트:

  • 2 부:속성에 대한 코드 내부를 보는 데에도 사용할 수 있나요?
  • 3부:공연은 어땠을까요?

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

속성 내에서 이를 사용하려면 .Substring(4)을 사용하여 'set_' 또는 'get_'을 제거하세요.

도움이 되었습니까?

해결책

.NET 4.5부터는 다음을 사용할 수도 있습니다. [발신자회원이름]

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

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

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

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

다른 팁

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

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

그러면 다음과 동일한 결과가 반환되어야 합니다. MethodBase.GetCurrentMethod().이름 기술이지만, 인덱스 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 https://stackoverflow.com/questions/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;
    }
}

결과

반사반사

스택트레이스스택트레이스

인라인상수인라인상수

끊임없는끊임없는

특급e => e.expr()

특급회원특급회원

발신자기본

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

참고 expr 그리고 callermember 방법은 "올바른" 것이 아닙니다.그리고 거기에서 다음과 같은 내용이 반복되는 것을 볼 수 있습니다. 관련 댓글 그 반영은 stacktrace보다 ~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)]

간단한 거래 방법은 다음과 같습니다.

System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name;

System.Reflection이 using 블록에 포함된 경우:

MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;

이건 어때요?

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

내 생각엔 당신이 그것을 만들면서 얻을 수 있어야 한다고 생각합니다. 스택트레이스.또는 @로가장자리 그리고 @라스 멜룸 MethodBase를 언급하세요.GetCurrent메소드()

메소드의 문자열 이름만 필요한 경우 표현식을 사용할 수 있습니다.보다 http://joelabrahamsson.com/entry/getting-property-and-method-names-using-static-reflection-in-c-sharp

이 시도...

    /// <summary>
    /// Return the full name of method
    /// </summary>
    /// <param name="obj">Class that calls this method (use Report(this))</param>
    /// <returns></returns>
    public string Report(object obj)
    {
        var reflectedType = new StackTrace().GetFrame(1).GetMethod().ReflectedType;
        if (reflectedType == null) return null;

        var i = reflectedType.FullName;
        var ii = new StackTrace().GetFrame(1).GetMethod().Name;

        return string.Concat(i, ".", ii);
    }

방금 간단한 정적 클래스를 사용하여 이 작업을 수행했습니다.

using System.Runtime.CompilerServices;
.
.
.
    public static class MyMethodName
        {
            public static string Show([CallerMemberName] string name = "")
            {
                return name;
            }
        }

그런 다음 코드에서 :

private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = MyMethodName.Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = MyMethodName.Show();
        }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top