泛型约束(转)
轉(zhuǎn)載自:http://blog.163.com/kele_lipeng/blog/static/8134527820121171056451/
一、泛型簡(jiǎn)介
1.1泛型
通過(guò)使用泛型,可以創(chuàng)建這樣的類、接口和方法,它們以一種類型安全的工作方式操作各種數(shù)據(jù)。
本質(zhì)上,術(shù)語(yǔ)“泛型”指的是“參數(shù)化類型”(parameterized types)。參數(shù)化類型非常重要,因?yàn)樗鼈兛梢栽趧?chuàng)建類、接口、方法和委托的時(shí)候?qū)⒁僮鞯臄?shù)據(jù)類型作為參數(shù)進(jìn)行指定。
通過(guò)泛型,可以創(chuàng)建一個(gè)類,使其自動(dòng)處理不同類型的數(shù)據(jù)。使用參數(shù)化類型的類、接口、方法和委托都可以稱為“泛型”。
可以通過(guò)使用object類型的引用來(lái)創(chuàng)建通用的類、接口、方法和委托。但這種方法的缺陷在于,無(wú)法保證類型安全。泛型彌補(bǔ)了無(wú)法保證類型安全的缺陷,也簡(jiǎn)化了處理的過(guò)程。因?yàn)椴辉傩枰獔?zhí)行object與實(shí)際操作的數(shù)據(jù)類型之間的轉(zhuǎn)換。
因此,泛型可以使開發(fā)人員最大限度地重用代碼,并使得代碼更加簡(jiǎn)單,更加安全。
泛型類型因類型參數(shù)的不同而不同。
理解泛型類型的一個(gè)關(guān)鍵在于,對(duì)某個(gè)泛型類型的一個(gè)版本的引用并不能與同一泛型類型的另一個(gè)版本相兼容。
1.2泛型如何實(shí)現(xiàn)類型安全?
泛型可以自動(dòng)確保有關(guān)的泛型類的所有操作都是類安全的。在處理過(guò)程中,泛型避免了手工進(jìn)行轉(zhuǎn)換和編寫類型檢查代碼的必要。
1.3泛型類的通用形式:
class class-name<type-param-list>{}聲明一個(gè)對(duì)泛型類的引用的語(yǔ)法:
class-name<type-arg-list> var-name=new class-name<type-arg-list>(cons-arg-list);舉例:
class GenericClass<T, V> {T data;//declare an object of type T V data2; public GenericClass(T obT, V ob2){data1 = ob1;data2 = ob2;}public T GetData(){return this.data;}public void ShowType(){Console.WriteLine("The type of T is : {0},The type of V is:{1}",typeof(T),typeof(V));} }在實(shí)際應(yīng)用中,我們往往會(huì)對(duì)類型T進(jìn)行一定的約束,以限制應(yīng)用區(qū)域。
二、類型約束(Constrained types)
2.1類型約束(Constrained types)
在指定一個(gè)類型參數(shù)時(shí),可以指定類型參數(shù)必須滿足的約束條件。這是通過(guò)在指定類型參數(shù)時(shí)使用where子句來(lái)實(shí)現(xiàn)的。
class class-name<type-param> where type-param:constraints{}
其中constraints是一個(gè)逗號(hào)分割的約束列表。
2.2五種約束類型
(1)可以使用“基類約束”(base class constraint)來(lái)指定某個(gè)基類必須出現(xiàn)在類型實(shí)參中。這種約束是通過(guò)指定基類名稱來(lái)實(shí)現(xiàn)的。
(2)可以使用“接口約束”(interface constraint)來(lái)指定某個(gè)類型實(shí)參必須實(shí)現(xiàn)一個(gè)或多個(gè)接口。這種約束是通過(guò)指定接口名稱來(lái)實(shí)現(xiàn)的。
(3)可以要求類型實(shí)參必須提供一個(gè)無(wú)參數(shù)的構(gòu)造函數(shù),這被稱為“構(gòu)造函數(shù)約束”(constructor constraint)。它是通過(guò)new()指定的。
(4)可以通過(guò)關(guān)鍵字class指定“引用類型約束”(reference type constraint)來(lái)限制某個(gè)類型實(shí)參必須是引用類型。
(5)可以通過(guò)關(guān)鍵字struct指定“值類型約束”(vlaue type constraint)來(lái)限制某個(gè)類型實(shí)參必須是值類型。
2.2.1 基類約束
使用基類約束,我們可以指定某個(gè)類型實(shí)參必須繼承的基類。
基類約束有兩個(gè)功能:
(1)它允許在泛型類中使用由約束指定的基類所定義的成員。例如,可以調(diào)用基類的方法或者使用基類的屬性。如果沒(méi)有基類約束,編譯器就無(wú)法知道某個(gè)類型實(shí)參擁有哪些成員。通過(guò)提供基類約束,編譯器將知道所有的類型實(shí)參都擁有由指定基類所定義的成員。
(2)確保類型實(shí)參支持指定的基類類型參數(shù)。這意味著對(duì)于任意給定的基類約束,類型實(shí)參必須要么是基類本身,要么是派生于該基類的類,如果試圖使用沒(méi)有繼承指定基類的類型實(shí)參,就會(huì)導(dǎo)致編譯錯(cuò)誤。
基類約束使用下面形式的where子句:
T是類型參數(shù)的名稱,base-class-name是基類的名稱,這里只能指定一個(gè)基類。
2.2.2 接口約束
接口約束用于指定某個(gè)類型參數(shù)必須應(yīng)用的接口。接口的兩個(gè)主要功能和基類約束完全一樣。
基本形式?
interface-name是接口的名稱,可以通過(guò)使用由逗號(hào)分割的列表來(lái)同時(shí)指定多個(gè)接口。
如果某個(gè)約束同時(shí)包含基類和接口,則先指定基類列表,再指定接口列表。
2.2.3 new()構(gòu)造函數(shù)約束
new()構(gòu)造函數(shù)約束允許開發(fā)人員實(shí)例化一個(gè)泛型類型的對(duì)象。
一般情況下,我們無(wú)法創(chuàng)建一個(gè)泛型類型參數(shù)的實(shí)例。然而,new()約束改變了這種情況,他要求類型參數(shù)必須提供一個(gè)無(wú)參數(shù)的構(gòu)造函數(shù)。
在使用new()約束時(shí),可以通過(guò)調(diào)用該無(wú)參構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象。
基本形式:?
使用new()約束時(shí)應(yīng)注意兩點(diǎn):
(1)它可以與其他約束一起使用,但是必須位于約束列表的末端。
(2)new()僅允許開發(fā)人員使用無(wú)參構(gòu)造函數(shù)來(lái)構(gòu)造一個(gè)對(duì)象,即使同時(shí)存在其他的構(gòu)造函數(shù)。換句話說(shuō),不允許給類型參數(shù)的構(gòu)造函數(shù)傳遞實(shí)參。
2.2.4 引用類型和值類型約束
如果引用類型和值類型之間的差別對(duì)于泛型代碼非常重要,那么這些約束就非常有用。
基本形式:
可以使用 struct 約束將一般類型參數(shù)約束為值類型(例如,int、bool 和 enum),或任何自定義結(jié)構(gòu):public?class?MyClass?where?T?:?struct ??
?{...}?
同樣,可以使用 class 約束將一般類型參數(shù)約束為引用類型(類):
public?class?MyClass?where?T?:?class? ?
?{...}?
若同時(shí)存在其他約束的情況下,class或struct必須位于列表的開頭。
另外可以通過(guò) 使用約束來(lái)建立兩個(gè)類型參數(shù)之間的關(guān)系
例如 class GenericClass2<T, V> where V:T{} -------- 要求V必須繼承于T,這種稱為裸類型約束(naked type constraint)
舉例:
class BaseC {int baseInt;string baseStr;public void Show(){Console.WriteLine("Something");} } //基類約束 class GenericClass3<T> where T : BaseC {T ob1;public void Show(){ob1.Show();} } //new()構(gòu)造函數(shù)約束 class GenericClass4<T> where T : new() {public T ob1;public GenericClass4(){ob1 = new T();} }2.2.5 default 關(guān)鍵字
泛型代碼中的默認(rèn)關(guān)鍵字(C# 編程指南)
在泛型類和泛型方法中產(chǎn)生的一個(gè)問(wèn)題是,在預(yù)先未知以下情況時(shí),如何將默認(rèn)值分配給參數(shù)化類型 T:
T 是引用類型還是值類型。
如果 T 為值類型,則它是數(shù)值還是結(jié)構(gòu)。
給定參數(shù)化類型 T 的一個(gè)變量 t,只有當(dāng) T 為引用類型時(shí),語(yǔ)句 t = null 才有效;只有當(dāng) T 為數(shù)值類型而不是結(jié)構(gòu)時(shí),語(yǔ)句 t = 0 才能正常使用。解決方案是使用 default 關(guān)鍵字,此關(guān)鍵字對(duì)于引用類型會(huì)返回空,對(duì)于數(shù)值類型會(huì)返回零。對(duì)于結(jié)構(gòu),此關(guān)鍵字將返回初始化為零或空的每個(gè)結(jié)構(gòu)成員,具體取決于這些結(jié)構(gòu)是值類型還是引用類型。
?
三、使用泛型類
在給泛型類傳遞類型實(shí)參的時(shí)候,實(shí)際創(chuàng)建的是C#中的“封閉構(gòu)建類型”(closed constructed type)。
術(shù)語(yǔ)“封閉”一詞,是指指定了類型實(shí)參,因此GenericClass<int>是一個(gè)封閉構(gòu)建類型。
本質(zhì)上,泛型類型,例如GenericClass<T>,是一種抽象結(jié)構(gòu)。只有在特定的版本(例如GenericClass<int>)被構(gòu)建以后才創(chuàng)建了一個(gè)實(shí)際的類型。
在C#中術(shù)語(yǔ)中,GenericClass<T>之類的構(gòu)造被稱為“開放構(gòu)建類型”(open constructed type),是因?yàn)樗麤](méi)有指定類型實(shí)參。
舉例:
public void Demo1()
{
?????? GenericClass<int,string> gen=new GenericClass<int,string>(12,"I am Chinese");?
?????? Console.Write("Type: ");
?????? gen.ShowType();
?????? Console.WriteLine("The first Data: " + gen.GetData());
}
//new()構(gòu)造函數(shù)約束
public void Demo2()
{
?????? GenericClass4<BaseC> demo4 = new GenericClass4<BaseC>();
?????? demo4.ob1.Show();
}
總結(jié):
①:default
??????在泛型中,要為某個(gè)使用泛型的變量初始化值,可是我們需要考慮的是這個(gè)泛型可能是引用類型,也可能是值類型,這時(shí)我們可以借助default來(lái)完成初始化復(fù)制。T value = default(T);如果T是引用類型,value = null,如果是T是值類型,value = 0.
②:where
????????????????????????????????????? ?約束????????????????????????????????????????????????????????????????? 說(shuō)明
??????????????????????????????? where T:struct???????????????????????????????????? 使用結(jié)構(gòu)約束,類型T必須是值類型
????????????????????????????????where T:class?????????????????????????????????????? 類約束指定,類型T必須是引用類型
??????????????????????????????? where T:IFoo?????????????????????????????????????????? ?指定類型T必須派生于接口IFoo
??????????????????????????????? where T:Foo????????????????????????????????????????????指定類型T必須派生于基類Foo
?????????????????????????????? where T:new()????????????????????????????????????? ?指定類型T必須有一個(gè)默認(rèn)構(gòu)造函數(shù)?
???????????????????????????????? where T:U??????????????????????????????????????????類型T派生于泛型類型V(裸類型約束)
???(注:在CRL2.0中,只能為默認(rèn)構(gòu)造函數(shù)定義約束,不能為其他構(gòu)造函數(shù)定義約束)
?四.泛型繼承
?如何實(shí)現(xiàn)C#泛型類的繼承呢?這里需要滿足下面兩點(diǎn)中的任何一點(diǎn)即可:
1、泛型類繼承中,父類的類型參數(shù)已被實(shí)例化,這種情況下子類不一定必須是泛型類;
2、父類的類型參數(shù)沒(méi)有被實(shí)例化,但來(lái)源于子類,也就是說(shuō)父類和子類都是泛型類,并且二者有相同的類型參數(shù);
//如果這樣寫的話,顯然會(huì)報(bào)找不到類型T,S的錯(cuò)誤???
public class TestChild : Test< T, S> { }??
//正確的寫法應(yīng)該是??
public class TestChild : Test< string, int>{ }??
public class TestChild< T, S> : Test< T, S> { }
轉(zhuǎn)載于:https://www.cnblogs.com/icyJ/archive/2013/01/05/generic.html
總結(jié)
- 上一篇: jenkins -ant-svn 自动化
- 下一篇: python做图像识别该学什么_Pyth