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

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

正如标题所说:"可以反射给您当前执行方法的名称。"

因为海森堡的问题,我倾向于不这样认为。如何在不更改当前方法的情况下调用一个方法来告诉您当前方法?但我希望有人能证明我错了。

更新:

  • 第2部分:这是否也可以用于查找属性的内部代码?
  • 第三部分:表演会是怎样的?

最终结果我了解了methodBase.getCurrentMethod()。我还了解到,我不仅可以创建一个堆栈跟踪,而且如果需要,我只能创建所需的确切帧。

要在属性中使用此函数,只需使用.substring(4)删除"set_uu"或"get_uu"。


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

http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx


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

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

1
2
3
4
5
6
7
8
9
10
    protected void SetProperty<T>(T value, [CallerMemberName] string property = null)
    {
        this.propertyValues[property] = value;
        OnPropertyChanged(property);
    }

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

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


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

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

这应该将相同的结果返回给methodBase.getcurrentMethod().name技术,但它仍然值得指出,因为我可以在它自己的方法中使用上一个方法的索引1实现这一点,并从许多不同的属性调用它。此外,它只返回一帧,而不是整个堆栈跟踪:

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

这也是一条单行线;)


在空控制台程序的主方法中尝试此操作:

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

控制台输出:Main


是的。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

这条线:

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

在堆栈框架中查找调用方法,然后使用反射获取传递给它的通用错误报告函数的参数信息值。要获取当前方法,只需使用当前堆栈帧(1)。

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

1
MethodBase.GetCurrentMethod()

我更喜欢遍历堆栈,因为如果从内部看这个方法,它只会创建一个StackCrawlMark。对我来说,直接寻址堆栈似乎更清晰

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

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

这似乎主要是一个针对inotifyPropertiesChanged支持的解决方案,以前在事件代码中到处都是字符串。


比较获取方法名的方法--在LinqPad中使用任意计时构造:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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;
    }
}

结果

反射反射

堆栈跟踪堆栈跟踪

内联常数内联常数

常数常数

EXPRE= > EXPRE()

Exp成员Exp成员

来电会员主要的

1
2
3
4
5
6
7
8
9
10
11
12
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方法并不完全"正确"。在这里,您可以看到重复的相关注释,反射比stacktrace快约15倍。


edit:methodbase可能是获取您所在方法的更好方法(而不是整个调用堆栈)。不过,我还是担心内线。

您可以在以下方法中使用stacktrace:

1
StackTrace st = new StackTrace(true);

看看这些框架:

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

但是,请注意,如果方法是内联的,那么您将不在您认为自己在方法中。可以使用属性来防止内联:

1
[MethodImpl(MethodImplOptions.NoInlining)]


简单的处理方法是:

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

如果system.reflection包含在using块中:

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

这个怎么样:

1
2
3
4
5
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

我认为您应该能够从创建stacktrace中得到它。或者,作为@edg和@lars m?hlum提述,methodbase.getcurrentmethod()


我只是用一个简单的静态类来做这个:

1
2
3
4
5
6
7
8
9
10
11
using System.Runtime.CompilerServices;
.
.
.
    public static class MyMethodName
        {
            public static string Show([CallerMemberName] string name ="")
            {
                return name;
            }
        }

然后在您的代码中:

1
2
3
4
5
6
7
8
9
private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = MyMethodName.Show();
        }

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


试试这个…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    /// <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);
    }

如果只需要方法的字符串名称,则可以使用表达式。请参阅http://joelabrahamsson.com/entry/getting-property-and-method-names-using-static-reflection-in-c-sharp