[C#] 015.使用dynamic來簡化反映Reflection ( 本範例以10000000(一千萬)次的執行比較。通常Dynamic都比Reflection 至少快14倍)

讀【157個完美化C#的建議】一書的理解筆記 - 015

重點:反映類別中的語法有兩種1.反射Reflection 2.Dynamic ,通常用Dynamic語法簡潔且比一般的Reflection快 (差14倍)

流程說明
1. FCL 1.0 的reflection
2. FCL 2.0 的dynamic
3. reflection與dynamic的效能比較
4. 結論

1. FCL 1.0 的reflection


我們有以下類別的內容

/// <summary>
/// 範例類別
/// </summary>
public class DyamicSample
{
    public string Name { get; set; }

    public int Add(int a, int b)
    {
        return a + b;
    }


}

在.net FrameWork Class Libary 1.0  的時代只有以下反射呼叫類別內的函式

取得Add的函式方法內容,然後進行委派(執行),取得result = 3

 //==== A  FCL 1.0 沒有Dynamic的時代,必須透過反射取得Method ====

DyamicSample origin = new DyamicSample();
//取得類別 DyamicSample 裡面的Method 名稱叫 Add ※如果沒有就是Null
var addMetohd = typeof(DyamicSample).GetMethod("Add");
//取得到後,可以對該方法進行委派,取得結果
int result = (int)addMetohd.Invoke(origin, new object[] { 1, 2 });

 


2. FCL 2.0 的dynamic


在.net FrameWork Class Libary 1.0  之後提供了dynamic,程式碼更簡潔了

//==== B  FCL 2.0 以後有了Dynamic 可以更快速、間單的取得Method ===
dynamic origin2 = new DyamicSample();
int result2 = origin2.Add(1, 2);

3. reflection與dynamic的效能比較


我們在主程式進行 1. 一般reflection  2.優化reflection (委派呼叫) 3.Dynamic

各跑10000000(一千萬次),比較效能,如下

//進行 10000000 次的比較,可以展顯出兩者差異
string rateResult = Compare(10000000);
textBox1.Text = rateResult;

Compare() 是基於以下比較的函式

/// <summary>
/// 比較反射與Dynamic的速度差異
/// </summary>
public string Compare(int times)
{
    string resultMessage = string.Empty;

    //----------以下是反射
    //建立碼表計時器
    Stopwatch sw = new Stopwatch();
    DyamicSample origin = new DyamicSample();
    var addMetohd = typeof(DyamicSample).GetMethod("Add");

    sw.Restart();
    for (int i = times; i > 0; i--)
    {
        addMetohd.Invoke(origin, new object[] { 1, 2 });
    }
    resultMessage += string.Format("反射(Reflect)耗費:{0} 毫秒  \r\n", sw.ElapsedMilliseconds);
    sw.Stop();

    //----------以下是反射 優化
    DyamicSample originPeformance = new DyamicSample();
    var addMetohdPeformance = typeof(DyamicSample).GetMethod("Add");
    //優化部分-執行委派 FCL 3.0提供以下方法
    var delegateObj = (Func<DyamicSample, int, int, int>)Delegate.CreateDelegate(
           typeof(Func<DyamicSample, int, int, int>),
           addMetohdPeformance
        );

    sw.Restart();
    for (int i = times; i > 0; i--)
    {
        delegateObj(originPeformance, 1, 2);
    }
    resultMessage += string.Format("反射優化(Reflect)耗費:{0} 毫秒  \r\n", sw.ElapsedMilliseconds);
    sw.Stop();


    dynamic dynamicObj = new DyamicSample();
    //----------以下是Dynamic
    sw.Restart();
    for (int i = times; i > 0; i--)
    {
        dynamicObj.Add(1, 2);
    }
    resultMessage += string.Format("Dynamic 耗費:{0} 毫秒  \r\n", sw.ElapsedMilliseconds);
    sw.Stop();


    return resultMessage;
}

得到出結果如下:


4.結論


在需要反射類別物件的情況下,建議用Dynamic,因為優化的Reflection雖然更快,但在千萬筆的執行中只差0.2秒,但失去了程式碼的乾淨

對於維護成本相對提高6倍 (軟體工程師每看一行Code 都是時間成本)。

10000000次的執行耗費時間 程式碼行數 評論
Reflection 5.8 秒 3行 效能差,不建議使用
優化Reflection 0.2 秒 6行 效能最佳,但程式碼失去簡潔,除非是巨型專案,才較推薦
Dynamic 0.4 秒 1行 效能不錯,程式碼簡潔,通常選擇

github連結(Vs2015) : 點我下載