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


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

     
    回答1

    For non-async methods one can use

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

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

    Please remember that for async methods it will return "MoveNext".

    回答2

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

    Example: a property setter (to answer part 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 call sites, so there is basically no performance overhead.

    回答3

     
     

    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:

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

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

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

    How performant is StackFrame?

    回答1
     

    edit: Some background


    We have a similar feature which is disabled 99% of the time; we were using an approach like:

    public void DoSomething()
    {
        TraceCall(MethodBase.GetCurrentMethod().Name);
        // Do Something
    }
    
    public void TraceCall(string methodName)
    {
        if (!loggingEnabled) { return; }
        // Log...
    }
    
    TraceCall(MethodBase.GetCurrentMethod().Name)

    It was simple, but regardless of whether or not tracing was enabled we were incurring the performance hit of using Reflection to lookup the method name.

    Our options were to either require more code in every method (and risk simple mistakes or refusal) or to switch to using StackFrame to determine the calling method only when logging was enabled.

    Option A:

    public void DoSomething()
    {
        if (loggingEnabled)
        {
            TraceCall(MethodBase.GetCurrentMethod().Name);
        }
        // Do Something
    }
    
    public void TraceCall(string methodName)
    {
        if (!loggingEnabled) { return; }
        // Log...
    }

    Option B:

    public void DoSomething()
    {
        TraceCall();
        // Do Something
    }
    
    public void TraceCall()
    {
        if (!loggingEnabled) { return; }
        StackFrame stackFrame = new StackFrame(1);
        // Log...
    }

    We opted for Option B. It offers significant performance improvements over Option A when logging is disabled, 99% of the time and is very simple to implement.

    Here's an alteration of Michael's code, to display the cost / benefit of this approach

    using System;
    using System.Diagnostics;
    using System.Reflection;
    
    namespace ConsoleApplication
    {
        class Program
        {
            static bool traceCalls;
    
            static void Main(string[] args)
            {
                Stopwatch sw;
    
                // warm up
                for (int i = 0; i < 100000; i++)
                {
                    TraceCall();
                }
    
                // call 100K times, tracing *disabled*, passing method name
                sw = Stopwatch.StartNew();
                traceCalls = false;
                for (int i = 0; i < 100000; i++)
                {
                    TraceCall(MethodBase.GetCurrentMethod());
                }
                sw.Stop();
                Console.WriteLine("Tracing Disabled, passing Method Name: {0}ms"
                                 , sw.ElapsedMilliseconds);
    
                // call 100K times, tracing *enabled*, passing method name
                sw = Stopwatch.StartNew();
                traceCalls = true;
                for (int i = 0; i < 100000; i++)
                {
                    TraceCall(MethodBase.GetCurrentMethod());
                }
                sw.Stop();
                Console.WriteLine("Tracing Enabled, passing Method Name: {0}ms"
                                 , sw.ElapsedMilliseconds);
    
                // call 100K times, tracing *disabled*, determining method name
                sw = Stopwatch.StartNew();
                traceCalls = false;
                for (int i = 0; i < 100000; i++)
                {
                    TraceCall();
                }
                Console.WriteLine("Tracing Disabled, looking up Method Name: {0}ms"
                           , sw.ElapsedMilliseconds);
    
                // call 100K times, tracing *enabled*, determining method name
                sw = Stopwatch.StartNew();
                traceCalls = true;
                for (int i = 0; i < 100000; i++)
                {
                    TraceCall();
                }
                Console.WriteLine("Tracing Enabled, looking up Method Name: {0}ms"
                           , sw.ElapsedMilliseconds);
    
                Console.ReadKey();
            }
    
            private static void TraceCall()
            {
                if (traceCalls)
                {
                    StackFrame stackFrame = new StackFrame(1);
                    TraceCall(stackFrame.GetMethod().Name);
                }
            }
    
            private static void TraceCall(MethodBase method)
            {
                if (traceCalls)
                {
                    TraceCall(method.Name);
                }
            }
    
            private static void TraceCall(string methodName)
            {
                // Write to log
            }
        }
    }

    The Results:

    Tracing Disabled, passing Method Name: 294ms
    Tracing Enabled,  passing Method Name: 298ms
    Tracing Disabled, looking up Method Name: 0ms
    Tracing Enabled,  looking up Method Name: 1230ms

    回答2

    I am considering using something like StackFrame stackFrame = new StackFrame(1) to log the executing method

    Out of interest: Why? If you only want the current method, then

    string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;

    seems better. Maybe not more performant (I didn't compare, but Reflection shows that GetCurrentMethod() does not simply create a StackFrame but does some "magic"), but clearer in it's intent.

  • 相关阅读:
    搜索引擎ElasticSearch系列(四): ElasticSearch2.4.4 sql插件安装
    搜索引擎ElasticSearch系列(三): ElasticSearch2.4.4 bigdesk插件安装
    搜索引擎ElasticSearch系列(二): ElasticSearch2.4.4 Head插件安装
    搜索引擎ElasticSearch系列(一): ElasticSearch2.4.4环境搭建
    LumiSoft.Net 收发邮件
    搜索引擎Solr6.2.1 索引富文本(word/pdf/txt/html)
    用异或提取出数组中的单独数
    买卖股票的最佳时机 II
    二叉树的路径总和
    SpringBeanUtils的部分方法类
  • 原文地址:https://www.cnblogs.com/chucklu/p/16426842.html
Copyright © 2020-2023  润新知