這些代碼在集合中存儲System.Object的引用,任何時候你都 可以使用它,在你訪問集合是,你必須添加強制轉換。但使用C#范型,你可以這 樣定義同樣的類:
public class List < ItemType >
{
private class Node < ItemType >
{
internal ItemType val;
internal Node < ItemType > next;
}
private Node < ItemType > first;
public void AddHead( ItemType t )
{
// ...
}
public ItemType Head( )
{
return first.val;
}
}
你可以用對象來代替ItemType, 這個參數類型是用於 定義類的。C#編譯器在實例化列表時,用恰當的類型來替換它們。例如,看一下 這樣的代碼:
List < int > intList = new List < int >();
MSIL可以精確的確保intList中存儲的是且只是整數 。比起目前你所實現的集合(譯注:這裡指C#1.1裡的集合),創建的范型有幾個 好處,首先就是,如果你試圖把其它任何不是整型的內容放到集合中時,C#的編 譯器會給出一個編譯錯誤,而現今,你須要通過測試運行時代碼來附加這些錯誤 。
在C#1.0裡,你要承擔裝箱和拆箱的一些損失,而不管你是從集合中移 出或者是移入一個值類型數據,因為它們都是以System.Object的引用形式存在 的。使用范型,JIT編譯器會為集合創建特殊的實例,用於存儲實際的值類型。 這樣,你就不用裝箱或者拆箱了。還不只這些,C#的設計者還想避免代碼的膨脹 ,這在C++模板裡是相關的。為了節約空間,JIT編譯器只為所有的引用類型生成 一個版本。這樣可以取得一個速度和空間上的平衡,對每個值類型(避免裝箱)會 有一個特殊的版本呢,而且引用類型共享單個運行時的版本用於存儲 System.Object (避免代碼膨脹)。在這些集合中使用了錯誤的引用時,編譯器還 是會報告錯誤。
為了實現范型,CLR以及MSIL語言經歷了一些修改。當你 編譯一個范型類時,MSIL為每一個參數化的類型預留了空間。考慮下面兩個方法 的申明MSIL:
To implement generics, the CLR and the MSIL language undergo some changes. When you compile a generic class, MSIL contains placeholders for each parameterized type. Consider these two method declarations in MSIL:
.method public AddHead (!0 t) {
}
.method public !0 Head () {
}
!0 就是 一個為一個類型預留的,當一個實際的實例被申明和創建時,這個類型才創建。 這就有一種替換的可能:
.method public AddHead (System.Int32 t) {
}
.method public System.Int32 Head () {
}
類似的,變化的實例包含特殊的類。前面的為整型的申 明就變成了為樣:
.locals (class List<int>)
newobj void List<int>::.ctor ()