.NET Framework泛型的作用
在CLR(common language runtime)1.0中,當要創建一個靈活的類或方法,但該類或方法在編譯期問不知道使用什麼類,就必須以System.Object類為基礎進行處理,而Object類在編譯期間沒有類型安全性,又必須進行強制類型轉換.另外,給值類型使用Object類會有性能損失,這給程式開發帶來諸多不便.故在CLR 2.0(.NET 3.5基於CLR 2.0)中,提供了泛型.
通過使用泛型類型,可以根據需要,用特定的類型替換泛型類型,同時保證了類型安全性:如果某個類型不支持泛型類,編譯器就會報錯,以阻止程度發生運行期錯誤.正確使用泛型將大大提高代碼的靈活性,結合一個優秀的設計模式,可以顯著縮短開發時間.
泛型的優勢
安 全
C#是一個類型安全的語言,類型安全允許編譯器(可信賴的)捕獲潛在的錯誤,而不是在程式運行時才發現(不可信賴的).在CLR1.0中,當使用集合時,這種類型安全就失效了:由.NET類庫提供的集合類全是存儲基類型(Object)的,而.NET中所有的一切都繼承於Object,因此所有類型都可以放到一個集合中,這相當於根本就沒有了類型檢測.下面的代碼也正好說明了這個問題.
ArrayListlist—new ArrayI.ist():list.Add(100);list.Add(“test”);list.Add(new object());foreach(int i in list)//引發運行期錯誤Console.Write(i);
可以往ArrayList里添加任何類型,也能通過編譯,但是在接下來的使用中,由於字元串“test”和Object對象都不能轉換為值類型int,這會拋出運行期錯誤,類型不再安全.
性 能
泛型的一個主要優點是性能.如果對值類型使用普通的集合類,在把值類型轉換為引用類型和把引用類型轉換成為值類型時,程式會進行裝箱和拆箱操作,性能損失比較大,操作疊代多次時尤其嚴重。而使用泛型能使程式在運行期間明確知道操作的對象的類型,可以減少拆箱和裝箱的操作。
ArrayList list—new Arraylist();liSt.Add(100);//裝箱:將值類型轉換為引用類型int i=(int)list[03;//拆箱:將引用類型轉換為值類型 foreach(int j in list)//拆箱 Console.Write(j);List<int>iist=new List<int>(); list.Add(100);//無裝箱:類型已經存儲在List< int> int i—listE0];///無拆箱:不需要進行類型轉換 foreach(int j in list) Console.Write(j);
重 用
泛型允許更好地重用代碼.泛型類可以只定義一次,用於不同的類型實例化,減少代碼量,如list<int>, List<string>,List<object>等等,且泛型可以在一種語言中定義,在另一種.NET語言中使用(如C#,VB.NET等).泛型編譯為II。(intermediate language)代碼時,是採用占位符來表示泛型類型,並用專有的IL指令支持泛型操作,所以用某個類型實例化泛型不會在IL代碼中複製這些類.為了說明,使用一個最簡單的泛型類class Test<T>{...},編譯運行後,使用Visual Studio自帶的IL反彙編程式打開生成的執行檔,定位到Test<T>類的構造函式,可以看到下面的代碼:
.method public hidebysig specialname rtspecialname instance void.ctor(!T 7value')cil managed{ IL-000a:stfld ! 0 class last.7Fest、1<! T>::-object}
可以看出,泛型類使用了占位符“T”來表示這個泛型所支持的類型參數,並不會生成多份Test類以適應不同的傳人類型.
真正的泛型實例化工作以“on-demand”的方式發生在JIT(Just—in time)編譯時,CLR為所有類型參數為“引用類型”的泛型類產生同一份代碼;但是如果類型參數為“值類型”,對每一個不同的“值類型”,CLR將為其產生一份獨立的代碼.
常用泛型
可空類型
C#中的值類型必須包含一個值,而引用類型可以為空(null),但是讓值類型可空是非常有用的(配合資料庫使用).所以,.NET提供了泛型System.Nullable<T>可以使值類型具備可空的性質,其中類型參數T必須是不可以為null的類型.因為可空類型使用得非常頻繁,所以C#有一種特殊的語法,使用“?”運算符,用於定義這種類型的變數,如int7.
泛型集合
System.Collection.Generic命名空間下有大量泛型集合類_J,圖1列示了幾個比較常用的泛型,它們使用起來都十分方便,.NET已經為這些類提供了完善的成員函式與屬性.
泛型的繼承
.NET已有的泛型的功能已經比較完善,但是如果想在其基礎上增加自定義的操作,可以定義一個泛型類並繼承.NET已有的泛型,見圖2.
需要注意的是,如果某個類型在它所繼承的基類型中受到約束,該類型就不能“解除約束”.也就是說,類型參數丁在基類中使用受到了某約束S,則在子類中T必須受到至少與基類型相同的約束.