2010-01-26 55 views
2

我一直在考慮是否可以應用DI模式而不會產生虛擬方法調用的代價(根據實驗,我的確可以比非虛擬調用慢4倍)。我的第一個想法是通過仿製藥做的依賴注入:.Net中的依賴注入沒有虛擬方法調用?

sealed class ComponentA<TComponentB, TComponentC> : IComponentA 
    where TComponentB : IComponentB 
    where TComponentC : IComponentC 
{ ... } 

不幸的是,CLR仍然沒有方法通過即使TComponentB和TComponentC的具體實現指定爲泛型類型參數,所有的類都是接口調用宣佈爲密封。獲得CLR執行非虛擬調用的唯一方法是將所有類更改爲結構(實現接口)。使用結構對於DI來說並不合適,並且使得下面的問題更加無法解決。

上述解決方案的第二個問題是它無法處理循環引用。我無法想出任何方法,無論是通過C#代碼還是通過構建表達式樹來處理循環引用,因爲這會導致無限遞歸泛型類型。 (.Net不支持引用自身的泛型類型,但似乎並沒有推廣到這種情況。)由於只有結構可以導致CLR繞過接口,所以我認爲這個問題根本不可解,因爲循環引用結構可能會導致矛盾。

我只能想到其他解決方案,它可以保證工作 - 在運行時從頭開始放置所有類,也許將它們作爲模板以編譯類爲基礎。雖然不是一個理想的解決方案。

任何人有更好的點子?

編輯:關於大多數評論,我想我應該說這是在「純粹的知識分子好奇心」下提出的,我辯論是否問這個問題是因爲我意識到我沒有任何具體的案例,這是必要的。我只是爲了好玩而思考它,並想知道是否有其他人遇到過。

+6

慢4倍?我覺得很難相信。我想這個文件「過早優化」下... – BFree 2010-01-26 18:53:16

+0

這是一個個人的,無期限的項目,所以我得到了過早的優化沉迷:) – jthg 2010-01-26 18:56:21

+0

@jthg - 過早的優化可以傷害的不僅僅是最後期限了。 – 2010-01-26 18:58:20

回答

2

雖然callvirt指令確實需要更長的時間,但通常會這樣做,因爲它在調用方法之前爲CLR提供便宜的null檢查。 A callvirt不應該比call指令長得多,特別是考慮到null檢查。

你有沒有發現,你可以顯著提高應用程序的創建類型(無論是structs或類的靜態方法),讓您保證C#編譯器會發出指令call而不是callvirt指令的性能?

我問的原因是我想知道是否要創建一個難以維護的代碼庫,這個代碼庫很脆弱,很難用於解決可能存在或可能不存在的問題。

+0

是的,使用結構確實減少了開銷幾乎沒有。我想我可能會錯誤地解釋改善的原因。 – jthg 2010-01-26 18:58:28

+0

使用結構也可以減少內存壓力,但是它們優化模型化問題域的能力有限。 – 2010-01-26 19:07:09

4

在我看來,試圖完全過度設計某些東西的典型例子。只要不要妥協你的設計,因爲你可以節省幾十毫秒 - 如果它甚至是。

你認真地暗示,因爲callvirt的說明,您的應用程序最終被如此顯著較慢的用戶(那些你寫的應用程序的人)會發現任何區別 - 呢?我非常懷疑。

3

這個blog post解釋了爲什麼你不能優化虛擬呼叫。

+0

這是一個很好的解釋。謝謝。 – jthg 2010-01-26 19:54:26