(一)泛型概述 泛型不僅是C#編程語言的一部分,而且與程序集中的IL代碼緊密地集成,。泛型不僅是C#語言的一種結(jié)構(gòu),,而且是CLR定義的。有了泛型就可以創(chuàng)建獨(dú)立于被包含類型的類和方法了,。 1,、性能 泛型的一個(gè)主要優(yōu)點(diǎn)就是性能,。對(duì)值類型使用非泛型集合類,在把值類型轉(zhuǎn)化為引用類型,,和把引用類型轉(zhuǎn)換為值類型時(shí),,需要進(jìn)行裝箱和拆箱操作。 下面的例子顯示了System.Collections名稱空間中的ArrayList類,。ArrayList存儲(chǔ)對(duì)象,,Add()方法定義為需要把對(duì)象作為參數(shù),所以要裝箱一個(gè)整數(shù)類型,。在讀取ArrayList中的值時(shí),,要進(jìn)行拆箱操作,把對(duì)象轉(zhuǎn)化為整數(shù)類型,??梢允褂妙愋脱b置轉(zhuǎn)換運(yùn)算符把ArrayList集合的第一個(gè)元素賦予變量i1,在訪問int類型的變量i2的foreach語句中,,也要使用類型強(qiáng)制轉(zhuǎn)換運(yùn)算符:
var list = new ArrayList();list.Add(44);//此處會(huì)裝箱int i1 = (int)list[0];//此處會(huì)拆箱foreach (int i2 in list){ Console.WriteLine(i2);//此處會(huì)拆箱}
System.Collections.Generic名稱空間中的List 下面的例子,。List 2,、類型安全 泛型的另一個(gè)特性是類型安全,。 在泛型類List 這個(gè)時(shí)候編譯器會(huì)報(bào)錯(cuò): 3,、二進(jìn)制代碼的重用 泛型允許更好地重用二進(jìn)制代碼,。泛型類可以定義一次,并且可以用許多不同的類型實(shí)例化,。 例如,,System.Collections.Generic名稱空間中的List 4,、代碼的擴(kuò)展 在不同的特定類型實(shí)例化泛型時(shí),,會(huì)創(chuàng)建多少代碼,?因?yàn)榉盒皖惖亩x會(huì)放在程序集中,所以用特定類型實(shí)例化泛型類不會(huì)再IL代碼中賦值這些類,。但是,,在JIT編譯器把泛型類編譯為本地代碼時(shí),會(huì)給每個(gè)值類型創(chuàng)建一個(gè)新類,。引用類型共享同一個(gè)本地類的所有相同的實(shí)現(xiàn)代碼,。這是因?yàn)橐妙愋驮趯?shí)例化的泛型類中只需要4個(gè)字節(jié)的內(nèi)存地址(32位系統(tǒng)),就可以引用一個(gè)引用類型,。值類型包含在實(shí)例化的泛型類的內(nèi)存中,,同時(shí)因為每個(gè)值類型對(duì)內(nèi)存的要求都不同,所以要為每個(gè)值類型實(shí)例化一個(gè)新類,。 5,、命名的約定 在程序中使用泛型,在區(qū)分泛型類型和非泛型類型時(shí)就會(huì)有一定的幫助,。下面是泛型類型的命名規(guī)則: l 泛型類型的名稱用字母T作為前綴,。 l 如果沒有特殊的要求,泛型類型允許使用任意類替代,,且只使用了一個(gè)泛型類型,,就可以用字符T作為泛型類型的名稱。 如果泛型類型有特定的要求(例如,,它必須實(shí)現(xiàn)一個(gè)接口或派生自基類),,或者使用了兩個(gè)或多個(gè)泛型類型,就應(yīng)給泛型類型使用描述性的名稱: (二)創(chuàng)建泛型類 泛型提供了一種新的創(chuàng)建類型的機(jī)制,,使用泛型創(chuàng)建的類型將帶有類型形參,。每個(gè)處理對(duì)象類型的類都可以有泛型實(shí)現(xiàn)方式。另外如果類使用了層次結(jié)構(gòu)就非常有助于消除類型強(qiáng)制轉(zhuǎn)換操作,。 (三)泛型類的功能 1,、默認(rèn)值 通過default關(guān)鍵字,將null賦予引用類型,,將0賦予值類型,。 default關(guān)鍵字根據(jù)上下文可以有多種含義。switch語句使用default定義默認(rèn)情況,。在泛型中,,根據(jù)泛型類型是引用類型還是值類型,泛型default用于將泛型類型初始化為null或0,。 2,、約束 在定義泛型類時(shí),可以對(duì)客戶端代碼能夠在實(shí)例化類時(shí)用于類型參數(shù)的類型種類施加限制,。如果客戶端代碼嘗試使用某個(gè)約束所不允許的類型來實(shí)例化類,,則會(huì)產(chǎn)生編譯時(shí)錯(cuò)誤,。這些限制稱為約束。約束是使用 where 上下文關(guān)鍵字指定的,。下表列出了六種類型的約束: 約束 說明 where T:struct 類型參數(shù)必須是值類型,。可以指定除 Nullable 以外的任何值類型,。 where T:Class 類型參數(shù)必須是引用類型,,包括任何類、接口,、委托或數(shù)組類型,。 where T:new() 類型參數(shù)必須具有無參數(shù)的公共構(gòu)造函數(shù)。當(dāng)與其他約束一起使用時(shí),,new() 約束必須最后指定,。 where T:基類名> 類型參數(shù)必須是指定的基類或派生自指定的基類。 where T:接口名稱> 類型參數(shù)必須是指定的接口或?qū)崿F(xiàn)指定的接口,??梢灾付ǘ鄠€(gè)接口約束。約束接口也可以是泛型的,。 where T1:T2 為 T1 提供的類型參數(shù)必須是為 T2 提供的參數(shù)或派生自為 T2 提供的參數(shù),。這稱為裸類型約束。 使用約束的原因 如果要檢查泛型列表中的某個(gè)項(xiàng)以確定它是否有效,,或者將它與其他某個(gè)項(xiàng)進(jìn)行比較,,則編譯器必須在一定程度上保證它需要調(diào)用的運(yùn)算符或方法將受到客戶端代碼可能指定的任何類型參數(shù)的支持。這種保證是通過對(duì)泛型類定義應(yīng)用一個(gè)或多個(gè)約束獲得的,。例如,,基類約束告訴編譯器:僅此類型的對(duì)象或從此類型派生的對(duì)象才可用作類型參數(shù)。一旦編譯器有了這個(gè)保證,,它就能夠允許在泛型類中調(diào)用該類型的方法,。約束是使用上下文關(guān)鍵字 where 應(yīng)用的。 使用泛型類型還可以合并多個(gè)約束: 3,、繼承 泛型類型可以實(shí)現(xiàn)泛型接口,,也可以派生自一個(gè)類(要求是必須重復(fù)接口或基類的泛型類型): 派生類也可以是泛型或非泛型的,其要求是必須制定基類的類型 4,、靜態(tài)成員 泛型類的靜態(tài)成員只能在類的一個(gè)實(shí)例中共享: 運(yùn)行以上代碼,,結(jié)果如下: 當(dāng)T類型不同時(shí)靜態(tài)成員不共享。 (四)泛型接口 使用泛型可以定義接口,,在泛型接口中定義的方法可以帶泛型參數(shù),。 協(xié)變和抗變指對(duì)參數(shù)和返回值類型進(jìn)行轉(zhuǎn)換。在.NET中參數(shù)類型時(shí)協(xié)變的,,返回類型是抗變的,。 1、協(xié)變和抗變 例子: 參數(shù)類型的協(xié)變 返回類型的抗變 例子: 2,、泛型接口的協(xié)變 如果泛型類型用out關(guān)鍵字進(jìn)行標(biāo)注,,泛型接口就是協(xié)變的。(子到父是協(xié)變) 3,、泛型接口的抗變 如果泛型類型用in關(guān)鍵字標(biāo)注,,泛型接口就是抗變的。 (五)泛型結(jié)構(gòu) 與類相似,結(jié)構(gòu)也可以是泛型的,。它們非常類似于泛型類,,只是沒有繼承特性。.NET Framework中的一個(gè)泛型結(jié)構(gòu)是Nullable 因?yàn)榭煽疹愋褪褂玫梅浅nl繁,所以C#有一種特殊的語法,,它用于定義可空類型的變量,。定義這類變量時(shí),不使用泛型結(jié)構(gòu)的語法,,而是用“?”運(yùn)算符,。 可以使用合并運(yùn)算符從可空類型轉(zhuǎn)換為非可空類型。合并運(yùn)算符“??” y的值顯示為0,,因?yàn)?/span>x是null,。 (六)泛型方法 除了定義泛型類之外,還可以定義泛型方法,。在泛型方法中,,泛型類型用方法聲明來定義。泛型方法可以在非泛型類中定義,。 C#編譯器會(huì)通過泛型方法來獲取參數(shù)類型,,所以不需要把泛型類型賦予方法的調(diào)用。 泛型方法可以像泛型方法那樣調(diào)用,。 1,、泛型方法示例 2、帶約束的泛型方法 因?yàn)榉椒ㄐ枰褂?/span>T參數(shù)的Name屬性,,所以為了確保程序不拋出異常,,對(duì)T參數(shù)進(jìn)行約束,使其必須繼承自People類,。 3,、帶委托的泛型方法 定義Cal方法,,參數(shù)t1,t2是calMethod方法的參數(shù)(Func是內(nèi)置的委托),。 4,、泛型方法規(guī)范 泛型方法可以重載,為特定的類型定義規(guī)范,。在編譯期間會(huì)使用最佳匹配,。 運(yùn)行以上代碼,結(jié)果如下: 需要注意的是,,所調(diào)用的方法是在編譯期間定義的,,而不是運(yùn)行期間。 運(yùn)行以上代碼,,結(jié)果如下: (七)小結(jié) 本章介紹了CLR中一個(gè)非常重要的特性:泛型,。通過泛型類可以創(chuàng)建獨(dú)立于類型的類,泛型方法是獨(dú)立于類型的方法,。接口,、結(jié)構(gòu)和委托也可以用泛型的方式創(chuàng)建。泛型引入了一種新的編程方式,。我們介紹了如何實(shí)現(xiàn)相應(yīng)的算法(尤其是操作和謂詞)以用于不同的類,,而且它們都是類型安全的。泛型委托可以去除集合中的算法,。 |
|