.NET Framework泛型是一個(gè)很強(qiáng)大的新特性,它為每一種對(duì)象生成一份單獨(dú)的代碼(也就是所謂的“實(shí)例化”),這一份量身頂做的代碼具有很高的效率,是強(qiáng)類型的,不需要運(yùn)行期多態(tài)的支持和負(fù)擔(dān),有了泛型,就不再需要Object類來參與實(shí)現(xiàn)一些通用類或方法了.
.NET Framework泛型的作用在CLR(common language runtime)1.0中,當(dāng)要?jiǎng)?chuàng)建一個(gè)靈活的類或方法,但該類或方法在編譯期問不知道使用什么類,就必須以System.Object類為基礎(chǔ)進(jìn)行處理,而Object類在編譯期間沒有類型安全性,又必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換.另外,給值類型使用Object類會(huì)有性能損失,這給程序開發(fā)帶來諸多不便.故在CLR 2.0(.NET 3.5基于CLR 2.0)中,提供了泛型.
通過使用泛型類型,可以根據(jù)需要,用特定的類型替換泛型類型,同時(shí)保證了類型安全性:如果某個(gè)類型不支持泛型類,編譯器就會(huì)報(bào)錯(cuò),以阻止程度發(fā)生運(yùn)行期錯(cuò)誤.正確使用泛型將大大提高代碼的靈活性,結(jié)合一個(gè)優(yōu)秀的設(shè)計(jì)模式,可以顯著縮短開發(fā)時(shí)間.
泛型的優(yōu)勢(shì)安 全C#是一個(gè)類型安全的語言,類型安全允許編譯器(可信賴的)捕獲潛在的錯(cuò)誤,而不是在程序運(yùn)行時(shí)才發(fā)現(xiàn)(不可信賴的).在CLR1.0中,當(dāng)使用集合時(shí),這種類型安全就失效了:由.NET類庫(kù)提供的集合類全是存儲(chǔ)基類型(Object)的,而.NET中所有的一切都繼承于Object,因此所有類型都可以放到一個(gè)集合中,這相當(dāng)于根本就沒有了類型檢測(cè).下面的代碼也正好說明了這個(gè)問題.
ArrayListlist—new ArrayI.ist():list.Add(100);list.Add(“test”);list.Add(new object());foreach(int i in list)//引發(fā)運(yùn)行期錯(cuò)誤Console.Write(i);可以往ArrayList里添加任何類型,也能通過編譯,但是在接下來的使用中,由于字符串“test”和Object對(duì)象都不能轉(zhuǎn)換為值類型int,這會(huì)拋出運(yùn)行期錯(cuò)誤,類型不再安全1.
性 能泛型的一個(gè)主要優(yōu)點(diǎn)是性能.如果對(duì)值類型使用普通的集合類,在把值類型轉(zhuǎn)換為引用類型和把引用類型轉(zhuǎn)換成為值類型時(shí),程序會(huì)進(jìn)行裝箱和拆箱操作,性能損失比較大,操作迭代多次時(shí)尤其嚴(yán)重。而使用泛型能使程序在運(yùn)行期間明確知道操作的對(duì)象的類型,可以減少拆箱和裝箱的操作。
ArrayList list—new Arraylist();liSt.Add(100);//裝箱:將值類型轉(zhuǎn)換為引用類型int i=(int)list[03;//拆箱:將引用類型轉(zhuǎn)換為值類型 foreach(int j in list)//拆箱 Console.Write(j);Listiist=new List(); list.Add(100);//無裝箱:類型已經(jīng)存儲(chǔ)在List int i—listE0];///無拆箱:不需要進(jìn)行類型轉(zhuǎn)換 foreach(int j in list) Console.Write(j);重 用泛型允許更好地重用代碼.泛型類可以只定義一次,用于不同的類型實(shí)例化,減少代碼量,如list, List,List等等,且泛型可以在一種語言中定義,在另一種.NET語言中使用(如C#,VB.NET等).泛型編譯為II。(intermediate language)代碼時(shí),是采用占位符來表示泛型類型,并用專有的IL指令支持泛型操作,所以用某個(gè)類型實(shí)例化泛型不會(huì)在IL代碼中復(fù)制這些類.為了說明,使用一個(gè)最簡(jiǎn)單的泛型類class Test{...},編譯運(yùn)行后,使用Visual Studio自帶的IL反匯編程序打開生成的可執(zhí)行文件,定位到Test類的構(gòu)造函數(shù),可以看到下面的代碼:
.method public hidebysig specialname rtspecialname instance void.ctor(!T 7value')cil managed{ IL-000a:stfld ! 0 class last.7Fest、1::-object}可以看出,泛型類使用了占位符“T”來表示這個(gè)泛型所支持的類型參數(shù),并不會(huì)生成多份Test類以適應(yīng)不同的傳人類型.
真正的泛型實(shí)例化工作以“on-demand”的方式發(fā)生在JIT(Just—in time)編譯時(shí),CLR為所有類型參數(shù)為“引用類型”的泛型類產(chǎn)生同一份代碼;但是如果類型參數(shù)為“值類型”,對(duì)每一個(gè)不同的“值類型”,CLR將為其產(chǎn)生一份獨(dú)立的代碼.
常用泛型可空類型C#中的值類型必須包含一個(gè)值,而引用類型可以為空(null),但是讓值類型可空是非常有用的(配合數(shù)據(jù)庫(kù)使用).所以,.NET提供了泛型System.Nullable可以使值類型具備可空的性質(zhì),其中類型參數(shù)T必須是不可以為null的類型.因?yàn)榭煽疹愋褪褂玫梅浅nl繁,所以C#有一種特殊的語法,使用“?”運(yùn)算符,用于定義這種類型的變量,如int7.
泛型集合System.Collection.Generic命名空間下有大量泛型集合類_J,圖1列示了幾個(gè)比較常用的泛型,它們使用起來都十分方便,.NET已經(jīng)為這些類提供了完善的成員函數(shù)與屬性.
泛型的繼承.NET已有的泛型的功能已經(jīng)比較完善,但是如果想在其基礎(chǔ)上增加自定義的操作,可以定義一個(gè)泛型類并繼承.NET已有的泛型,見圖2.
需要注意的是,如果某個(gè)類型在它所繼承的基類型中受到約束,該類型就不能“解除約束”.也就是說,類型參數(shù)丁在基類中使用受到了某約束S,則在子類中T必須受到至少與基類型相同的約束.
本詞條內(nèi)容貢獻(xiàn)者為:
王慧維 - 副研究員 - 西南大學(xué)