2016年6月1日 星期三

C# 取得呼叫的功能名稱, Get Caller Member Name, Performance Compared

Refer: http://stackoverflow.com/questions/1044519/get-property-name-inside-setter

取得呼叫的功能名稱,

public static int Dummy {
    get {
        var propertyName = MethodBase.GetCurrentMethod().Name.Substring(4);
        Console.WriteLine(propertyName);
        return 0;
    }
}
public static int Dummy {
    get {
        var propertyName = MethodInfo.GetCurrentMethod().Name.Substring(4);
        Console.WriteLine(propertyName);
        return 0;
    }
}

CallerMemberName 功能是 .NetFrameWork 4.5以後的功能,

Refer: https://msdn.microsoft.com/zh-tw/library/system.runtime.compilerservices.callermembernameattribute(v=vs.110).aspx

版本資訊
Universal Windows Platform
自 4.5 起可用
.NET Framework
自 4.5 起可用
Portable Class Library
支援版本:portable .NET platforms
Windows Phone Silverlight
自 8.0 起可用
Windows Phone
自 8.1 起可用

private static object GetSessionValue([CallerMemberName]string propertyName = "") 
{
    return Session[propertyName];
}

private static void SetSessionValue(object value, [CallerMemberName]string propertyName = "") 
{
    Session[propertyName] = value;
}

public int MyIndex
{
    get { return (int)GetSessionValue(); }
    set { SetSessionValue(value); }
}

【Performance,實測效能】

使用Visual Studio 2013開發,.Net Framework 4.5,
各跑10000次的時間:

MethodInfo:		00:00:00.0222161
CallerMemberName:	00:00:00.0006698
MethodBase:		00:00:00.0183167
StackFrame:		00:00:00.0870535
StackTrace:		00:00:00.1230636
Constant String:	00:00:00.0005125
MethodInfo與MethodBase基本大致上是接近的。
StackFrame與StackTrace在執行時需要new出來,可能因此花了多一些時間。
Constant String與CallerMemberName兩者也是接近的,猜想CallerMemberName在編譯時就寫入固定字串了。

Code: Program.cs


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2_testCallerMemberName
{
    class Program
    {
        static StackFrame sf;
        static void Main(string[] args)
        {
            sf = new StackFrame();
            TestGetFunctionName cs = new TestGetFunctionName();
            Stopwatch sw = new Stopwatch();

            sw.Start();
            for (int i = 0; i < 10000; i++)
            {
                string f = cs.field1;
            }
            sw.Stop();
            Console.WriteLine(GetString("MethodInfo", sw));

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000; i++)
            {
                string f = cs.field2;
            }
            sw.Stop();
            Console.WriteLine(GetString("CallerMemberName",sw));

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000; i++)
            {
                string f = cs.field3;
            }
            sw.Stop();
            Console.WriteLine(GetString("MethodBase", sw));

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000; i++)
            {
                string f = cs.field4;
            }
            sw.Stop();
            Console.WriteLine(GetString("StackFrame", sw));

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000; i++)
            {
                string f = cs.field5;
            }
            sw.Stop();
            Console.WriteLine(GetString("StackTrace", sw));

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000; i++)
            {
                string f = cs.field6;
            }
            sw.Stop();
            Console.WriteLine(GetString("Constant String", sw));

            Console.WriteLine("END");
            Console.ReadKey();
        }

        static string GetString(string method, Stopwatch sw)
        {
            return string.Format("{0}:\t\t{1}", method, sw.Elapsed);
        }
    }

    class TestGetFunctionName
    {
        public string field1 { get { return Log1(MethodInfo.GetCurrentMethod().Name.Substring(4)); } }

        public string field2 { get { return Log2(); } }

        public string field3 { get { return Log3(MethodBase.GetCurrentMethod().Name.Substring(4)); } }

        public string field4 { get { return Log4(new StackFrame().GetMethod().Name.Substring(4)); } }

        public string field5 { get { return Log5(new StackTrace().GetFrame(0).GetMethod().Name.Substring(4)); } }

        public string field6 { get { return Log6("field6"); } }

        private string Log6(string p)
        {
            return p;
        }

        private string Log5(string p)
        {
            return p;
        }

        private string Log4(string p)
        {
            return p;
        }

        private string Log3(string p)
        {
            return p;
        }

        string Log1(string field) { return field; }

        string Log2([CallerMemberName]string field = "") { return field; }
    }
}

沒有留言: