.net 可以使用反射来查找当前正在执行的方法的名称吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 09:43:42  来源:igfitidea点击:

Can you use reflection to find the name of the currently executing method?

.netreflection

提问by Joel Coehoorn

Like the title says: Can reflection give you the name of the currently executing method.

就像标题说的:可以反射给你当前正在执行的方法的名称。

I'm inclined to guess not, because of the Heisenberg problem. How do you call a method that will tell you the current method without changing what the current method is? But I'm hoping someone can prove me wrong there.

我倾向于猜测不是,因为海森堡问题。你如何调用一个方法来告诉你当前的方法而不改变当前的方法是什么?但我希望有人能证明我错了。

Update:

更新:

  • Part 2: Could this be used to look inside code for a property as well?
  • Part 3: What would the performance be like?
  • 第 2 部分:这也可以用于查看属性的内部代码吗?
  • 第 3 部分:性能如何?

Final Result
I learned about MethodBase.GetCurrentMethod(). I also learned that not only can I create a stack trace, I can create only the exact frame I need if I want.

最终结果
我了解了 MethodBase.GetCurrentMethod()。我还了解到,我不仅可以创建堆栈跟踪,还可以根据需要仅创建所需的确切帧。

To use this inside a property, just take a .Substring(4) to remove the 'set_' or 'get_'.

要在属性中使用它,只需使用 .Substring(4) 删除“set_”或“get_”。

采纳答案by John Nilsson

As of .NET 4.5 you can also use [CallerMemberName]

从 .NET 4.5 开始,您还可以使用[CallerMemberName]

Example: a property setter (to answer part 2):

示例:属性设置器(回答第 2 部分):

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

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

The compiler will supply matching string literals at callsites, so there is basically no performance overhead.

编译器将在调用站点提供匹配的字符串文字,因此基本上没有性能开销。

回答by Ed Guiness

For non-asyncmethods one can use

对于非async方法可以使用

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

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

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

Please remember that for asyncmethods it will return "MoveNext".

请记住,对于async方法,它将返回“MoveNext”。

回答by Joel Coehoorn

The snippet provided by Lex was a little long, so I'm pointing out the important part since no one else used the exact same technique:

Lex 提供的代码片段有点长,所以我指出了重要的部分,因为没有其他人使用完全相同的技术:

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

This should return identical results to the MethodBase.GetCurrentMethod().Nametechnique, but it's still worth pointing out because I could implement this once in its own method using index 1 for the previousmethod and call it from a number of different properties. Also, it only returns one frame rather then the entire stack trace:

这应该返回与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);
}

It's a one-liner, too ;)

它也是单线的 ;)

回答by Lars M?hlum

Try this inside the Main method in an empty console program:

在空控制台程序的 Main 方法中试试这个:

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

Console Output:
Main

控制台输出:
Main

回答by Lex

Yes definitely.

当然是。

If you want an object to manipulate I actually use a function like this:

如果你想要一个对象来操作,我实际上使用这样的函数:

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

This line:

这一行:

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

Walks up the stack frame to find the calling method then we use reflection to obtain parameter information values passed to it for a generic error reporting function. To get the current method simply use current stack frame (1) instead.

沿着堆栈帧向上查找调用方法,然后我们使用反射获取传递给它的参数信息值,用于通用错误报告函数。要获取当前方法,只需使用当前堆栈帧 (1)。

As others have said for the current methods name you can also use:

正如其他人所说的当前方法名称,您也可以使用:

MethodBase.GetCurrentMethod()

I prefer walking the stack because if look internally at that method it simply creates a StackCrawlMark anyway. Addressing the Stack directly seems clearer to me

我更喜欢遍历堆栈,因为如果在内部查看该方法,它无论如何都会创建一个 StackCrawlMark。直接寻址堆栈对我来说似乎更清楚

Post 4.5 you can now use the [CallerMemberNameAttribute] as part of the method parameters to get a string of the method name - this may help in some scenarios (but really in say the example above)

在 4.5 之后,您现在可以使用 [CallerMemberNameAttribute] 作为方法参数的一部分来获取方法名称的字符串 - 这在某些情况下可能会有所帮助(但实际上在上面的示例中)

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

This seemed to be mainly a solution for INotifyPropertyChanged support where previously you had strings littered all through your event code.

这似乎主要是 INotifyPropertyChanged 支持的解决方案,以前您的事件代码中到处都是字符串。

回答by drzaus

Comparing ways to get the method name -- using an arbitrary timing constructin LinqPad:

比较获取方法名称的方法——在 LinqPad 中使用任意计时结构

CODE

代码

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

RESULTS

结果

reflectionreflection

反射反射

stacktracestacktrace

堆栈跟踪

inlineconstantinlineconstant

内联常量

constantconstant

常数常数

expre => e.expr()

expre => e.expr()

exprmemberexprmember

exprmemberexprmember

callermemberMain

callermember

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


Note that the exprand callermembermethods aren't quite "right". And there you see a repetition of a related commentthat reflection is ~15x faster than stacktrace.

请注意,exprcallermember方法并不完全“正确”。在那里你看到重复的相关评论,反射比堆栈跟踪快约 15 倍。

回答by denis phillips

EDIT: MethodBase is probably a better way to just get the method you're in (as opposed to the whole calling stack). I'd still be concerned about inlining however.

编辑: MethodBase 可能是获取您所在方法的更好方法(与整个调用堆栈相反)。但是,我仍然会担心内联。

You can use a StackTrace within the method:

您可以在方法中使用 StackTrace:

StackTrace st = new StackTrace(true);

And the look at the frames:

看看框架:

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

However, be aware that if the method is inlined, you will not be inside the method you think you are. You can use an attribute to prevent inlining:

但是,请注意,如果该方法是内联的,则您将不在您认为的方法内部。您可以使用属性来防止内联:

[MethodImpl(MethodImplOptions.NoInlining)]

回答by SharK

The simple way to deal is:

简单的处理方法是:

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

If the System.Reflection is included in the using block:

如果 System.Reflection 包含在 using 块中:

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

回答by jesal

How about this this:

这个怎么样:

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

回答by bdukes

I think you should be able to get that from creating a StackTrace. Or, as @edgand @Lars M?hlummention, MethodBase.GetCurrentMethod()

我认为您应该能够通过创建StackTrace来获得它。或者,正如@edg@Lars M?hlum提到的,MethodBase。获取当前方法()