這樣做的優勢在於,首先通過GenericClass<T>為數組中的項提供了類型安全。在StandardClass中可能會這樣寫代碼:
// 一般類
StandardClass C = new StandardClass(5);
Console.WriteLine(C);
string s1 = "s1";
string s2 = "s2";
string s3 = "s3";
int i1 = 1;
// 在一般類中以object的形式添加項
C.AddItem(s1);
C.AddItem(s2);
C.AddItem(s3);
// 在字符串數組中添加一個整數,也被允許
C.AddItem(i1);
但在GenericClass<T>中做同樣的事情將導致編譯錯誤:
// 泛型類
GenericClass<string> gC = new GenericClass<string>(5);
Console.WriteLine(gC);
string s1 = "s1";
string s2 = "s2";
string s3 = "s3";
int i1 = 1;
// 把字符串添加進泛型類.
gC.AddItem(s1);
gC.AddItem(s2);
gC.AddItem(s3);
// 嘗試在字符串實例中添加整數,將被編譯器拒絕
// error CS1503: Argument '1': cannot convert from 'int' to 'string'
//GC.AddItem(i1);
編譯器防止它成為運行時源碼的bug,這是一件非常美妙的事情。
雖然並非顯而易見,但在StandardClass中把整數添加進object數組會導致裝箱操作,這一點可以StandardClass調用GetItem方法時的IL代碼:
Il _0170: ldloc.2
Il _0171: ldloc.s i1
Il _0173: box [mscorlib]System.Int32
Il _0178: callvirt instance int32 CSharpRecipes.Generics/StandardClass::AddItem(object)
這個裝箱操作把做為值類型的整數轉換為引用類型(object),從而可以在數組中存儲。這導致了在object數組中存儲值類型時需要增加額外的工作。
當您在運行StandardClass並從類中返回一個項時,還會產生一個問題,來看看StandardClass.GetItem如何返回一個項:
// 存儲返回的字符串.
string sHolder;
// 發生錯誤CS0266:
// Cannot implicitly convert type 'object' to 'string'…
sHolder = (string)C.GetItem(1);
因為StandardClass.GetItem返回的是object類型,而您希望通過索引1獲得一個字符串類型,所以需要把它轉換為字符串類型。然而它有可能並非字符串-----只能確定它是一個object-----但為了賦值正確,您不得不把它轉換為更明確的類型。字符串比較特殊,所有對象都可以自行提供一個字符串描述,但當數組接收一個double類型並把它賦給一個布爾類型就會出問題。
這兩個問題在GenericClass<T>中被全部解決。無需再進行拆箱,因為GetItem所返回的是一個具體類型,編譯器會檢查返回值以強近它執行。
string sHolder;
int iHolder;
// 不需要再進行轉換
sHolder = gC.GetItem(1);
// 嘗試把字符串變為整數.將出現
// 錯誤CS0029: Cannot implicitly convert type 'string' to 'int'
//iHolder = gC.GetItem(1);