2016-02-26 24 views
3

我正面臨一點困境。動態轉換vs反射調用:選擇哪種毒藥?

我需要重複調​​用某個類型的許多實例上的給定方法,這些實例可能存在也可能不存在。因爲對於任何給定的實例,該方法的結果永遠不會改變,所以我將緩存它的返回值以供將來使用,以便在隨後的調用中儘早減少開銷並返回,但仍然是實際上需要調用該方法的那部分方法方法 - 即五月 - 不存在

var method = Context.Parent.GetType().GetMethod("typeHint"); 
if (method == null) 
{ 
    token = null; 
    _hasTypeHint = false; 
    return false; 
} 

var hint = ((dynamic)Context.Parent).typeHint() as VBAParser.TypeHintContext; 
token = hint == null ? null : hint.GetText(); 
return hint != null; 

捕獲/處理一個RuntimeBinderException是一個重大的性能瓶頸,所以我決定,以反映對有問題的類型去發現之前調用該方法是否存在它。

Context.Parent的具體類型在編譯時是未知的,並且可能的運行時類型不共享一個公共接口,該接口將使用我正在尋找的typeHint()方法:我需要調用反射成員,或者投到dynamic並直接調用它。

我的提交消息是這樣的:

通過反映上下文類型來定位使用的方法除去的可能性爲RuntimeBinderException。 保留(動態)投射,因爲視爲比反射調用更便宜..雖然可能是錯誤的。

哪一個招致的開銷最少,更重要的是爲什麼

+0

爲什麼開銷會讓你擔心嗎?你是否在緊密的循環中多次調用這個方法? – dasblinkenlight

+0

@dasblinkenlight我正在迭代(至少)數百個實例(取決於數據)的類型,所以耶非常。剖析它就像在大海撈針中找到針一樣。 –

+0

當我面對這些類型的問題時,我立即開始考慮異步技術。我知道使用反射很昂貴,但如果你需要分離多少線程,可能不是那麼多,對吧?我不明白動態代碼是如何工作的,而且必須更深入地研究它。 –

回答

1

嗯,我很好奇,所以我寫了一個小程序來測試:

 var sw = new Stopwatch(); 
     int loopLimit = 10000000; 
     object hint1; 
     sw.Start(); 
     for(var i = 0; i < loopLimit; i++) 
      hint1 = ((dynamic)theObject).ToString(); 
     sw.Stop(); 
     Console.WriteLine("dynamic time: {0}", sw.ElapsedMilliseconds); 
     sw.Restart(); 
     for(var i = 0; i < loopLimit; i++) 
      hint1 = method.Invoke(theObject, null); 
     sw.Stop(); 
     Console.WriteLine("invoke time: {0}", sw.ElapsedMilliseconds); 
     Console.ReadLine(); 

loopLimit不同的價值觀播放你會看到相對較少的電話號碼Invoke會更快。當您增加loopLimit時,動態調用會變得更快,然後變得更快。爲什麼?因爲動態調用會緩存執行操作所需的表達式樹。在這種情況下,只創建了一個表達式樹,因爲我沒有更改theObject(在調用站點上,每個對象類型只有一個表達式樹)。因此,長話短說,如果您只調用了幾千次,或者如果您有多種對象類型來測試和調用,那麼表達式樹的創建將會消除您的性能,並且Invoke會更好。如果對象可以是幾種類型之一,並且您的方法被調用了數百萬次,那麼使用dynamic調用可能會更好。

玩你的特定情況的數字。我的猜測是你會選擇Invoke

+0

太棒了,我不知道表達樹參與!所以,如果我理解正確,我實際上更好地使用反射。謝謝! –

0

不知道這是否會爲你工作....

public async Task<tokenclass> Process(Button Context){ 
      var x = await Task.Run(() => 
      { 
       tokenclass tc = new tokenclass(); 
       var method = Context.Parent.GetType().GetMethod("typeHint"); 
       if (method == null) 
       { 
        tc.token = null; 
        tc.hasTypeHing = false; 
        tc.result = false;     
       } 
       return tc; 
      }); 
      return x; 


    public class tokenclass 
    { 
     public string token { get; set; } 
     public bool hasTypeHing { get; set; } 
     public bool result { get; set; } 
    } 
+0

不會在任務內產生新的任務(代碼已經從異步任務中調用)會產生*更多*開銷?我編輯了OP來包含'token'位,如果它令人困惑,很抱歉。 –

+0

它可以但你可以測試它來確保。我有一臺帶有7個CPU和大量內存的筆記本電腦,所以我與您提到的問題有些隔離。 –