2010-08-17 110 views
6

這樣做有什麼意義嗎?拳擊,過去的事情?

public static void Write<T>(T value) 
{ 
    textWriter.Write(value.ToString()); 
} 

...作爲應該這樣:

public static void Write(object value) 
{ 
    textWriter.Write(value.ToString()); 
} 

撇開明顯的空取消引用可能性,如果我在哪裏可以使用這種方法寫了很多類型的值不會前者是多少更好,因爲它會有它自己的寫入方法的調用版本,或者它會讓很多額外的代碼生成的二進制文件膨脹?

這種事情的性能意義可能可以忽略不計,但我很好奇,它比BCL中的每個值類型都提供了過載,比BCL中的大多數作者已經做的要好得多。

回答

7

從我的理解,在這兩種情況下拳擊發生。

後者是顯而易見的,因爲價值已經盒裝。

前者不太明顯,但由於虛擬方法在valuetype上被調用,因此需要將其裝箱以執行callvirt

編輯:我剛剛檢查了發射的IL,並且在通用情況下沒有發生明確的裝箱。東西響起了一個鐘。

編輯2:我可能一直在困惑自己與使用接口的情況。有明顯的拳擊發生。

編輯3:如果ToString()未在值類型中重寫,則會發生拳擊。

我得到這個從ECMA-335第3部分第25頁(僅指出最後一種情況下):

如果thisType是值類型和 thisType不實現方法 然後PTR被廢棄時,盒裝,和 作爲「這個」指針 callvirt方法的傳遞

這最後一種情況下只能發生時 方法定義於System.Object, System.ValueTypeSystem.Enum和 方法定義爲此類型。在這種 最後一種情況下,拳擊引起 原始對象的副本進行, 然而,由於上 System.ObjectSystem.ValueTypeSystem.Enum不修改的 對象狀態的所有方法,這個事實不能 檢測。

編輯4:Here is a similar question on SO

+0

所有的方法調用真的是虛擬的嗎?我懷疑只有界面方面才能使拳擊變得必要,現在@編輯3有點令人驚訝。我認爲這是相反的方式,儘管值類型有點不同,因爲你不能繼承,所以實際上不能在值類型和btw上使用虛方法,這是一個很好的答案! – 2010-08-17 16:40:19

1
  • 虛擬呼叫可以要求拳擊(如leppie已經說過)
  • 一般是在源更加緊湊,而不是在JIT'ed代碼

考慮性能:

  • 泛型有點降低二進制大小。 JIT時間和代碼局部性保持不變,因爲只有所需的過載纔會發生反正
  • 如果該方法不是像本例中那樣簡單化,那麼拳擊解決方案將涉及更少的JIT調用並減少代碼大小(從而也改善了局部性) 。除極端情況外,這是一種難以衡量的積累效應。

的要點是:沒有一種適用於所有情況的完美方法。

+0

實際上,我只是發現,在所有情況下都不需要裝箱(例如,在某個值類型中虛擬方法被重寫的地方):)請參閱我的修改。 – leppie 2010-08-17 06:18:42

+0

啊..有趣。增加了黃鼠狼的單詞;) – peterchen 2010-08-17 06:30:20

1

是的,它會避免大多數情況下的拳擊。儘管如此,我不希望在大多數情況下會產生顯着的性能差異。正如你自己所說,這可能是微不足道的。

我認爲它確實雖然增加了可讀性方面的負擔。我懷疑大多數人在嘗試理解泛型方法時比認爲使用object的簡單方法有更多的認知負荷。誰將會使用這種方法,並且他們對泛型非常滿意,不會打擾他們?