第十二章 泛型
目錄:
12.1 FCL中的泛型
12.2 泛型基礎(chǔ)結(jié)構(gòu)
12.3 泛型接口
12.4 泛型委托
12.5 委托和接口的逆變和協(xié)變泛型類型實(shí)參
12.6 泛型方法
12.7 泛型和其他成員
12.8 可驗(yàn)證性和約束
?
泛型時(shí)CLR和編程語言提供的一種特殊機(jī)制,它支持另一種形式的代碼重用,即“算法重用”。
大多數(shù)算法允許都封裝在一個(gè)類型中,CLR允許創(chuàng)建泛型引用類型和泛型值類型,但不允許創(chuàng)建泛型枚舉類型。CLR還允許創(chuàng)建泛型接口和泛型委托。方法偶爾也封裝有用的算法,所以CLR允許在引用類型,值類型或接口中定義泛型方法。
定義泛型類型或方法時(shí),為類型指定的任何變量(比如T)都稱為類型參數(shù)。T是變量名,源代碼能使用數(shù)據(jù)類型的任何地方都能使用T。
使用泛型類型或方法時(shí)指定的具體數(shù)據(jù)類型稱為類型實(shí)參。
優(yōu)勢(shì):
源代碼保護(hù):使用泛型算法的開發(fā)人員不需要訪問算法的源代碼。
類型安全:將泛型算法應(yīng)用于一個(gè)具體的類型時(shí),編譯器和CLR能理解開發(fā)人員的意圖,并保證只有與指定數(shù)據(jù)類型兼容的對(duì)象才能用于算法。
更清晰的代碼:由于編譯器強(qiáng)制類型安全性,所以減少了源代碼中必須進(jìn)行的強(qiáng)制類型轉(zhuǎn)換次數(shù),使代碼易于編寫和維護(hù)。
更佳的性能:CLR不需要執(zhí)行裝箱操作,值類型的實(shí)例以傳值的方式傳遞。
12.1 FCL中的泛型
泛型最明顯的應(yīng)用就是集合類。集合類型實(shí)現(xiàn)了許多接口,放入集合中的對(duì)象可實(shí)現(xiàn)接口來執(zhí)行排序和搜索等操作。
12.2 泛型基礎(chǔ)結(jié)構(gòu)
CLR添加泛型需要的工作:
創(chuàng)建新的IL指令,使之能夠識(shí)別類型參數(shù)。
修改現(xiàn)有元數(shù)據(jù)表的格式,以便表示具有泛型參數(shù)的類型名稱和方法。
修改各種編程語言(C#,Microsoft Visual Basic .NET等)來支持新語法,允許開發(fā)人員定義和引用泛型類型和方法。
修改編譯器,使之能生成新的IL指令和修改的元數(shù)據(jù)格式。
修改JIT編譯器,以便處理新的支持類型實(shí)參的IL指令來生成正確的本機(jī)代碼。
創(chuàng)建新的反射成員,使開發(fā)人員能查詢類型和成員,以判斷它們是否具有泛型參數(shù)。另外,還必須定義新的反射成員,使開發(fā)人員能在運(yùn)行時(shí)創(chuàng)建泛型類型和方法定義。
修改調(diào)試器以顯示和操縱泛型類型,成員,字段以及局部變量。
修改VS的“智能感知”功能。將泛型類型或方法應(yīng)用于特性數(shù)據(jù)類型時(shí)能顯示成員的原型。
12.2.1 開放類型和封閉類型
具有泛型類型參數(shù)的類型成為開發(fā)類型,CLR禁止構(gòu)造開放類型的任何實(shí)例。這類似于CLR禁止構(gòu)造接口類型的實(shí)例。
代碼引用泛型類型時(shí)可指定一組泛型類型實(shí)參。為所有類型參數(shù)都傳遞了實(shí)際的數(shù)據(jù)類型,類型就成為封閉類型。CLR允許構(gòu)造封閉類型的實(shí)例。然而,代碼引用泛型類型的時(shí)候,可能留下一些泛型類型實(shí)參未指定。這會(huì)在CLR中創(chuàng)建新的開發(fā)類型對(duì)象,而且不能創(chuàng)建該類型的實(shí)例。
12.2.2 泛型類型和繼承
泛型類型仍然時(shí)類型,所以能從其他任何類型派生。使用泛型類型并指定類型實(shí)參時(shí),實(shí)際是在CLR中定義一個(gè)新的類型對(duì)象,新的類型對(duì)象從泛型類型派生自的那個(gè)類型派生。
12.2.3 泛型類型同一性
12.2.4 代碼爆炸
使用泛型類型參數(shù)的方法在進(jìn)行JIT編譯時(shí),CLR獲取方法的IL,用指定的類型實(shí)參替換,然后創(chuàng)建恰當(dāng)?shù)谋緳C(jī)代碼(這些代碼未操作指定數(shù)據(jù)類型“量身定制”)。缺點(diǎn):CLR要為每種不同的方法/類型組合生成本機(jī)代碼。這個(gè)現(xiàn)象時(shí)“代碼爆炸”。
CLR內(nèi)建了一些優(yōu)化措施能緩解代碼爆炸。假如為特定的類型實(shí)參調(diào)用了一個(gè)方法,以后再用相同的類型實(shí)參調(diào)用這個(gè)方法,CLR只會(huì)為這個(gè)方法/類型組合編譯一次代碼。
CLR還有另一優(yōu)化,它認(rèn)為所有引用類型實(shí)參都完全相同,所以代碼能夠共享。(所有引用類型的參數(shù)或變量實(shí)際上只是指向堆上對(duì)象的指針,所有對(duì)象指針都以相同方式操縱)
如果某個(gè)類型時(shí)值類型,CLR就必須專門為那個(gè)值類型生成本機(jī)代碼。因?yàn)橹殿愋偷拇笮〔欢?#xff0c;CLR無法共享代碼,因?yàn)榭赡芤貌煌谋緳C(jī)CPU指令來操縱這些值。
12.3 泛型接口
使用非泛型接口來操縱值類型會(huì)發(fā)生裝箱,而且會(huì)失去編譯時(shí)的類型安全性。更到內(nèi)容請(qǐng)參考在13章接口
12.4 泛型委托
CLR支持泛型委托,目的是保證任何類型的對(duì)象都能以類型安全的方式傳給回調(diào)函數(shù)。泛型委托允許值類型實(shí)例在傳給給回調(diào)方法時(shí)不進(jìn)行任何裝箱。?
12.5 委托和接口的逆變和協(xié)變泛型類型實(shí)參
委托的每個(gè)泛型類型參數(shù)都可標(biāo)記為協(xié)變量或逆變量。這樣就可將泛型委托類型的變量轉(zhuǎn)換為相同的委托類型(但泛型參數(shù)類型不同)。泛型類型參數(shù):
不變量:意味著泛型類型參數(shù)不能更改。
逆變量:意味著泛型類型參數(shù)可以從一個(gè)類更改為它的某個(gè)派生類。在C#中用in關(guān)鍵字標(biāo)記逆變量形式的泛型類型參數(shù)。逆變量泛型類型參數(shù)只出現(xiàn)在輸入位置,比如作為方法的參數(shù)。
協(xié)變量:意味著泛型類型參數(shù)可以從一個(gè)類更改為它的某個(gè)基類。C#是用out關(guān)鍵字標(biāo)記協(xié)變量形式的泛型類型參數(shù)。協(xié)變量泛型類型參數(shù)只能出現(xiàn)在輸出位置,比如作為方法的返回類型。
(協(xié)變性指定返回類型的兼容性,逆變性指定參數(shù)的兼容性)
對(duì)于泛型類型參數(shù),如果要將該類型的實(shí)參傳給使用out或ref關(guān)鍵的方法,便不允許可變性。
12.6 泛型方法
定義泛型類,結(jié)構(gòu)或方法時(shí),類型中定義的任何地方都可引用類型指定的類型參數(shù)。類型參數(shù)可作為方法參數(shù),方法返回值或方法內(nèi)部定義的局部變量的類型使用。CLR也允許方法指定它自己的類型參數(shù)。這些參數(shù)也可以作為參數(shù),返回值,或局部變量使用。
泛型方法和類型推斷
C#編譯器支持在調(diào)用泛型方法時(shí)進(jìn)行類型推斷。這意味著編譯器會(huì)在調(diào)用泛型方法時(shí)自動(dòng)推斷要使用的類型。
12.7 泛型和其他成員
在C#中,屬性,索引器,事件,操作符方法,構(gòu)造器和終結(jié)器本身不能有類型參數(shù)。但它們能在泛型類型中定義,而且這些成員中的代碼能使用類型的類型參數(shù)。
12.8 可驗(yàn)證性和約束
?約束機(jī)制:約束的作用是限制能指定成泛型實(shí)參的類型數(shù)量。通過限制類型的數(shù)量,可以對(duì)那些類型執(zhí)行更多操作。
約束可應(yīng)用于泛型類型的類型參數(shù),也可用于泛型方法的類型參數(shù)。CLR不允許基于類型參數(shù)名稱或約束來進(jìn)行重載;只能基于元數(shù)(類型參數(shù)個(gè)數(shù))對(duì)類型或方法進(jìn)行重載。
重寫虛泛型方法時(shí),重寫的方法必須指定相同數(shù)量的類型參數(shù),而且這些類型參數(shù)繼承在基類方法上指定的約束。事實(shí)上,根本不允許為重寫方法的類型參數(shù)指定任何約束。但類型參數(shù)的名稱是可以改變的。類似地,實(shí)現(xiàn)接口方法時(shí),方法必須指定與接口方法等量地類型參數(shù),這些類型參數(shù)將繼承由接口方法指定地約束。
12.8.1 主要約束
類型參數(shù)可以指定零個(gè)或者一個(gè)主要約束。主要約束可以代表非密封類地一個(gè)引用類型。
指定引用類型約束時(shí),相當(dāng)于向編譯器承諾:一個(gè)指定的類型實(shí)參要么時(shí)與約束類型相同的類型,要么時(shí)從約束類型派生的類型。
12.8.2 次要約束
類型參數(shù)可以指定零個(gè)或者多個(gè)次要約束,次要約束代表接口類型。這種約束向編譯器承諾類型實(shí)參實(shí)現(xiàn)了接口。由于能指定多個(gè)接口約束,所以類型實(shí)參必須實(shí)現(xiàn)了所有接口約束。
還有一種次要約束稱為類型參數(shù)約束,有時(shí)也稱為裸類型約束。這種約束用得比接口約束少得多。它允許一個(gè)泛型類型或方法規(guī)定:指定的類型實(shí)參要么就是約束的類型,要么時(shí)約束的類型的派生類。一個(gè)類型參數(shù)可以指定零個(gè)或者多個(gè)類型參數(shù)約束。
12.8.3 構(gòu)造器約束
類型參數(shù)可指定零個(gè)或一個(gè)構(gòu)造器約束,它向編譯器承諾類型實(shí)參是是實(shí)現(xiàn)了公共無參構(gòu)造器的非抽象類型。where T : new()
12.8.4 其他可驗(yàn)證性問題
1.泛型類型變量的轉(zhuǎn)型
將泛型類型的變量轉(zhuǎn)型為其他類型是非法的,除非轉(zhuǎn)型為與約束兼容的類型。
2.將泛型類型變量設(shè)為默認(rèn)值
將泛型類型變量設(shè)為null是非法的,除非將泛型類型約束成引用類型。
3.將泛型類型變量與null進(jìn)行比較
無論泛型類型是否被約束,使用==或!=操作符將泛型類型變量與null進(jìn)行比較都是合法的。
4.兩個(gè)泛型類型變量相互比較
如果泛型類型參數(shù)不能肯定是引用類型,對(duì)同一個(gè)泛型類型的兩個(gè)變量進(jìn)行比較是非法的。
5.泛型類型變量作為操作數(shù)使用
將操作符應(yīng)用于泛型類型操作數(shù)會(huì)出現(xiàn)大量問題。不能將操作符應(yīng)用于泛型類型的變量。
?
轉(zhuǎn)載于:https://www.cnblogs.com/terry-1/p/10028569.html
總結(jié)
- 上一篇: 纸条app怎么复制(纸条作文app下载最
- 下一篇: 罗技G610和ikbcF410哪个好(罗