代码之家  ›  专栏  ›  技术社区  ›  Joel Coehoorn

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

  •  188
  • Joel Coehoorn  · 技术社区  · 16 年前

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

    更新:

    • 第2部分:这也可以用来查找属性的内部代码吗?
    • 第三部分:表演会是什么样子?

    最终结果

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

    13 回复  |  直到 16 年前
        1
  •  191
  •   Victor Yarema    5 年前

    非- async 可以使用的方法

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

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

    请记住这一点 异步的 方法它将返回“MoveNext”。

        2
  •  127
  •   Pang firemonkey    4 年前

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

        3
  •  48
  •   Joel Coehoorn    16 年前

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

    这也是一条单行线;)

        4
  •  18
  •   Lars Mæhlum    16 年前

    在空控制台程序的Main方法中尝试以下操作:

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

    控制台输出:
    Main

        5
  •  12
  •   Lex    11 年前

    当然可以。

    如果你想操纵一个对象,我实际上使用了如下函数:

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

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

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

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

        6
  •  12
  •   Community datashaman    7 年前

    比较获取方法名的方法--使用 arbitrary timing construct 在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;
        }
    }
    

    后果

    反射

    堆栈跟踪

    内联常数 内联常数

    常数

    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
    

    expr callermember 方法不太“正确”。在这里你可以看到重复的 a related comment 该反射比stacktrace快约15倍。

        7
  •  9
  •   JacquesB    16 年前

    编辑: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)]
    
        8
  •  7
  •   Sunny Patel    8 年前

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

    如果系统反射包含在使用块中:

    MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;
    
        9
  •  4
  •   Pang firemonkey    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
    
        10
  •  2
  •   Community datashaman    7 年前

    我认为你应该能够通过创建一个 StackTrace . 或者@ edg 及@ Lars Mæhlum 提到,MethodBase。 GetCurrentMethod ()

        11
  •  2
  •   mr R    4 年前
    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
    
        12
  •  2
  •   Pang firemonkey    4 年前

    我只是通过一个简单的静态类实现了这一点:

    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();
    }
    
        13
  •  1
  •   Useme Alehosaini    3 年前

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

    //using System.Reflection;
    
    var myMethodName = MethodBase
                        .GetCurrentMethod()
                        .DeclaringType
                        .Name
                        .Substring(1)
                        .Split('>')[0];
    
        14
  •  1
  •   Paul Williams    3 年前

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

    [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;
    }
    
        15
  •  0
  •   Adriano Silva Ribeiro    9 年前

    试试这个。。。

        /// <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);
        }
    
        16
  •  0
  •   Chef Gladiator    3 年前

    从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
  •   David Buck Richard Ferris    4 年前
    new StackTrace().ToString().Split("\r\n",StringSplitOptions.RemoveEmptyEntries)[0].Replace("at ","").Trim()
    
        18
  •  -1
  •   Romerik Rousseau    4 年前

    将此方法添加到某个地方,然后不带参数地调用它!

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