泛型、型別參數、建構的型別

泛型可用於類別、介面、委派、和方法。這裡要先介紹的是宣告泛型類別的基本語法:



其中以角括弧 < > 符號包住的 T1, T2,..., Tn 即是所謂的型別參數(type parameters),也就是先前提過的「變動的部分」。型別參數可有一至多個,端看實際的需要而定。慣例上,型別參數的名稱通常以一個大寫英文字母 ‘T’ 開頭,如果只有一個型別參數,通常就單純命名為 “T”,例如:List<T>。若有多個型別參數,則建議使用望文生義的名稱,以便識別。像 .NET 的泛型集合 Dictionary<TKey, TValue> 就很清楚,一看就知道這個泛型集合所要儲存的每一筆資料都包含兩種元素:key(索引鍵)與value(資料值),而這兩種元素的真正型別,則是等到實際要使用集合物件的時候才以參數的方式帶入。

請注意「類別名稱<T>」並不是真正用來建立物件實體的類別,而只是一個類別的樣板(template)──你不能直接用類別樣板來建立物件實體。當我們在程式中使用泛型來建立物件時,必須指定欲帶入的型別參數,例如 Dictionary<int, string> 或 Dictionary<string, Employee> 等等,而這些有帶入型別參數的類別,才是程式執行時真正使用的類別。這些「真正的類別」有個正式稱呼,叫做「建構的型別」(constructed type)或「關閉的型別」(closed type)。相對的,由於在宣告泛型的時候會提供一些型別參數,開放讓外界指定實際要用的型別,故使用泛型語法所宣告的型別又稱為「開放的型別」(open type)。

泛型是型別的樣板

在學習物件導向程式語言的時候,有一個很常見的譬喻:類別就像是一張藍圖,而物件則是根據該藍圖所建立出來的實體(instance);只要先把藍圖設計好,我們就可以在程式中利用該藍圖來建立多個物件實體。同樣的譬喻也可以用來理解泛型。我們可以說,泛型就是類別的藍圖(樣板),根據此藍圖,便能夠產生多種建構的型別;然後,再利用這些建構的型別來建立物件實體。下圖描繪了泛型、建構的型別、與物件實體這三者之間的關係。


雖然您已經知道 .NET Framework 已經有提供現成的泛型串列,現在假設您因為某些特殊原因需要設計自己的泛型串列,並將它命名 MyGenericList。程式碼如下:


其中的 T 即為型別參數。您不妨與前面的 IntList 和 StringList 類別的程式碼對照一下,其中以黃色背景醒目標示者即為差異的部分。你可以看到,只要需要用到型別參數的部分,都是以型別參數名稱 T 來表示。等到真正需要使用建構的型別(constructed type)時,編譯器便會以外部指定的型別帶入參數 T,以產生真正的類別。完整起見,底下再列出實際建立物件時的程式範例:


此例中,根據泛型 MyGenericList 所建構的型別共有兩個,分別是 MyGenericList 和 MyGenericList,而程式便是利用這兩個建構的型別來各自建立不同的物件實體。圖3所示即為編譯器根據我們定義的泛型來產生建構型別的示意圖。圖的左方為泛型類別的宣告,右方為編譯器所產生的建構型別。當編譯器看到 MyGenericList 時,就會將型別 Employee 帶入泛型的型別參數 T,從而產生一個新的型別(即建構的型別),如圖中右邊的區塊所示。


注意:這裡的「編譯器」指的是 .NET 即時編譯器(just-in-time compiler),而非 C# 編譯器;這個部分會在稍後的<泛型與 C++ 樣板的差異>一節中進一步說明。

以上內容摘自:C# 學習筆記-泛型

Post Comments

技術提供:Blogger.