你能用反射来找到当前正在执行的方法的名称吗?

时间:2008-09-04 16:45:36

标签: .net reflection

如标题所示:反射可以为您提供当前正在执行的方法的名称。

由于海森堡的问题,我倾向于不猜。如何在不改变当前方法的情况下调用一种方法来告诉您当前的方法?但我希望有人可以证明我错了。

更新:

  • 第2部分:这可以用于查看属性的内部代码吗?
  • 第3部分:表现如何?

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

要在属性中使用它,只需使用.Substring(4)删除'set_'或'get _'。

19 个答案:

答案 0 :(得分:182)

答案 1 :(得分:108)

从.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); }
    }

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

答案 2 :(得分:46)

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

这也是一个单行;)

答案 3 :(得分:15)

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

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

控制台输出:
Main

答案 4 :(得分:12)

肯定是。

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

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。直接解决堆栈似乎对我来说更清楚

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

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

这似乎主要是INotifyPropertyChanged支持的解决方案,之前您在事件代码中遍布了字符串。

答案 5 :(得分:11)

比较获取方法名称的方法 - 在LinqPad中使用arbitrary timing construct

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

结果

<强>反射 反思

<强>栈跟踪 stacktrace

<强> inlineconstant inlineconstant

<强>常数

<强> EXPR e =&gt; e.expr()

<强> exprmember exprmember

<强> 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

请注意,exprcallermember方法并不完全“正确”。在那里你看到重复a related comment反射比堆栈跟踪快〜15倍。

答案 6 :(得分:9)

编辑: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)]

答案 7 :(得分:6)

简单的处理方式是:

YYYY-MM-DDThh:mm:ss.msZ

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

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

答案 8 :(得分:4)

这个怎么样:

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

答案 9 :(得分:2)

我认为您应该能够通过创建StackTrace来实现这一目标。或者,@ edg和@ Lars Mæhlum提及,MethodBase。GetCurrentMethod()

答案 10 :(得分:2)

using System;
                    
public class Program
{
    public static void Main()
    {
        
        Console.WriteLine("1: {0} {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, System.Reflection.MethodBase.GetCurrentMethod().ReflectedType);
        OtherMethod();
    }
    
    public static void OtherMethod()
    {
        Console.WriteLine("2: {0} {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, System.Reflection.MethodBase.GetCurrentMethod().ReflectedType);
    }
}

输出:

1: Main Program
2: OtherMethod Program

答案 11 :(得分:1)

对于 Async 方法,您可以使用:

//using System.Reflection;

var myMethodName = MethodBase
                    .GetCurrentMethod()
                    .DeclaringType
                    .Name
                    .Substring(1)
                    .Split('>')[0];

答案 12 :(得分:1)

为了处理异步和普通的旧方法调用,我这样做了。

在我的应用程序中,它只从异常处理程序中调用,因此性能不是问题。

[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCurrentMethodName()
{
    var st = new StackTrace();
    var sf = st.GetFrame(1);
    string name = sf.GetMethod().Name;

    if (name.Equals("MoveNext"))
    {
        // We're inside an async method
        name = sf.GetMethod().ReflectedType.Name
                 .Split(new char[] { '<', '>' }, StringSplitOptions.RemoveEmptyEntries)[0];
    }

    return name;
}

答案 13 :(得分:0)

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

答案 14 :(得分:0)

试试这个......

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

答案 15 :(得分:0)

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

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

答案 16 :(得分:0)

从 2021 年开始为客户提供更具弹性的解决方案:

namespace my {
   public struct notmacros
   {

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string 
  whoami( [CallerMemberName] string caller_name = null)
  {
     if (string.IsNullOrEmpty(caller_name)) 
        return "unknown";
     if (string.IsNullOrWhiteSpace(caller_name)) 
        return "unknown";
     return caller_name;
  }
 }
} // my namespace

用法

using static my.notmacros
 // somewhere  appropriate
 var my_name = whoami() ;

答案 17 :(得分:-1)

new StackTrace()。ToString()。Split(“ \ r \ n”,StringSplitOptions.RemoveEmptyEntries)[0] .Replace(“ at”,“”)。Trim()

答案 18 :(得分:-1)

将此方法添加到某处并在不带参数的情况下调用它!

public static string GetCurrentMethodName([System.Runtime.CompilerServices.CallerMemberName] string name = "")
{
    return name;
}