Visual Studio 2005 為 Microsoft .NET 架構帶來了泛型程式設計的型別參數化模型。當然,型別參數化是C++程式員的事情。所以,對於那些還不熟悉它們的人,我將在本文中對泛型程式設計做一個簡要的介紹。
泛型程式設計的基本思想是交付固定的程式碼程式庫,這個程式碼程式庫支援潛在的無限類型集合。有兩種用於泛型程式設計的常規模型:通用類型容器模型(Universal Type Container Model,UTCM)和型別參數化模型(Type Parameter Model,TPM)。
在 UTCM 中,與對象相關的類型資訊已經被剝離。因為它是可還原的,所以容易實現。所有的對象都以一種統一的、非透明的方式儲存。而在一個像 CTS(Common Type System)這樣單一的類型體系中,通用類型容器就是即 Object;所有的 CTS 類型均直接或間接地的從 Object 中派生。比如說 C 語言中,void * 就是 通用類型。
在 TPM 中,與對象關聯的類型資訊的綁定已經被提煉和延遲。從一個調用到另一種調用中,值的變化多種多樣,它們被提煉為參數。這就是為什麼這種實現模型被稱為參數化 類型的原因——它更複雜,但功能強大。
例如,你在實現一個 System::Collections 名字空間的 IEnumerator 介面。只要提供兩個方法和一個屬性,好像很簡單。但是在強型別語言中,提供對所有使用者都可用的單一介面其難度是無法想象的。其難就難在我們的實現中 無法再使用“???”;
interface class IEnumerator
{
property ??? Current { ??? get(); }
bool MoveNext();
void Reset();
};
類型系統需要你靜態標識與屬性的儲存空間回填相關的類型以及擷取存取器(accessor)傳回型別,但這當然是不可能的。使用者需要枚舉的潛在類型無以計數。你怎麼辦?
簡單一點的常規解決辦法是 UTCM,在這裡對象被作為容器。
interface class IEnumerator
{
property Object^ Current { Object^ get(); }
bool MoveNext();
void Reset();
};
這樣提供了一定程度上的隔離。它允許用單一不變的程式碼程式庫來支援潛在的無窮多的類型。並且對於被動儲存和參考型別對象的擷取,其工作表現不俗。
一旦你你需要象混凝土類型那樣來擷取和處理該對象,事情就變得有些不那麼雅緻了。這要求向下強制轉換為最初的物件類型。不幸的是,編譯器沒有必要的類型資訊來保證 強制類型轉換的正確性,從而造成程式員得手工顯式向下轉換,如下例所示:
extern void f( Object^ anyTypeWorks );
Object^ o = "a string of all things";
// no downcast ... passive storage
f( o );
// downcast ... we need to manipulate
String^ s = safe_cast<String^>( o );
在實現集合時碰到的問題更多,因為無法靜態約束某個集合在通用類型容器模型下僅容納單一類型的對象。這隻能從程式一級提供,而且稍顯複雜和易錯。此外,因為它是一個程式解決方案,只能被用於運行時期。 你再次得不到編譯器的支援。
除了安全性和複雜性之外,還涉及大規模儲存以及在通用類型容器模型下擷取實值型別的效能問題。藉助型別參數化,這三個問題迎刃而解。