【问题标题】:Getting the caller method name - Reflection and CallerInfo attribute获取调用者方法名称 - 反射和 CallerInfo 属性
【发布时间】:2014-04-08 06:49:34
【问题描述】:

刚刚对使用StackTraceCallerInfo Attributes 的性能进行了基准测试。

令人震惊的是,我发现使用StackTrace 的速度要快得多,尽管我在每个地方都看到To get the caller method name, the preferred approach is CallerInfo attributes

public class Program
    {
        public static void Main(string[] args)
        {
          Method1();  
        }

         static void Method1([CallerMemberName]string memberName = "")
         {
            double stackTraceTimings = 0;
            var sw = new Stopwatch();

            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
               sw.Start();
               var callerName = new StackFrame(1).GetMethod().Name;
               sw.Stop();
               stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using StackFrame in 1000 iterations ={0}",stackTraceTimings/1000);

            stackTraceTimings = 0;
            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
                sw.Start();
                var callerName = (memberName);
                sw.Stop();
                stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using callerInfo Attribute in 1000 iterations ={0}",stackTraceTimings/1000);
        }

输出: 在 1000 次迭代中使用 StackFrame 检索调用方名称的经过时间 =9.48074760000001

在 1000 次迭代中使用 callerInfo 属性检索来电者姓名所用的时间 =21.7074064

我是不是误会了什么?使用CallerInfo 属性是首选方法吧?

感谢以下答案的指出。

每次循环中我都必须重新启动计时器。

那么,谁赢了?正如下面的答案所说,@ 987654327@。因为,它是一个编译时特性,而且速度更快。

在 1000 次迭代中使用 StackFrame 检索调用方名称所用的时间 =0.00762619999999992

在 1000 次迭代中使用 callerInfo 属性检索来电者姓名所用的时间 =0.00639420000000002

我使用了下面的代码(修改后的),得到了上面的结果。

 public class Program
    {
        public static void Main(string[] args)
        {
          Method1();  
        }

         static void Method1([CallerMemberName]string memberName = "")
         {
            double stackTraceTimings = 0;
            var sw = new Stopwatch();

            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
               sw.Start();
               var callerName = new StackFrame(1).GetMethod().Name;
               sw.Stop();
               Console.Write(callerName);
               sw.Restart();
               stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using StackFrame in 1000 iterations ={0}",stackTraceTimings/1000);


            stackTraceTimings = 0;
            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
                sw.Start();
                var callerName = (memberName);
                Console.Write(callerName);
                sw.Stop();
                sw.Restart();

                stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using callerInfo Attribute in 1000 iterations ={0}",stackTraceTimings/1000);
        }
    }

【问题讨论】:

  • 您是在调用 CallerMemberNameAttribute“callerInfo”吗?令人困惑。

标签: c# .net reflection .net-4.5 callermembername


【解决方案1】:

您必须在第二个循环之前重置计时器。 sw.Start 从第一个循环之后的状态开始 Stopwatch,所以第二个结果实际上是 StackTrace 和基于属性的解决方案加在一起的时间。

CallerMethodName 是编译类型的功能,它肯定会更快。

在您的结果中,CallerMethodName 的固定代码时间是:

21.7074064 - (9.48074760000001 * 2) = 2.7459111999999806

这样更快,不是吗?

第一次减去两次:一次是因为缺少Reset 调用,一次是因为+= 而不是=

更新

这些结果似乎太大了。 您确定您使用的是从 Visual Studio 外部运行的 Release 版本吗?我认为不是,否则您会得到完全相同的结果:callerName 从未使用过,可能会被优化到无操作(至少在第二种情况下)。

【讨论】:

  • 是的,你是对的。谢谢指点。我会更新帖子。 :)
  • 哦!我正在使用在线编译器。不是 Visual Studio,因为我暂时不用。
  • 我打印了methodNames来防止callerName is never used and will probably be optimized to no-op (at least for second case).并把更新后的结果放上去
猜你喜欢
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
  • 2011-10-27
  • 2011-03-06
相关资源
最近更新 更多