2013年9月11日 星期三

[轉貼] 泛型的條件約束 Constraints


前篇介紹了 泛用方法,接下來再筆記一下條件約束。
條件約束有三種:型別條件約束、New 條件約束、限制參考型別或是數值型別的條件約束

型別條件約束
若是需要限制某個型別參數是繼承某一個類別或是實作一或多個介面。
01public class MyGenericCollection
02<KeyType,ElementType>
03where KeyType : IComparable
04where ElementType : System.Web.UI.WebControls.WebControl
05{
06    ...
07}
08 
09//編譯發生錯誤
10MyGenericCollection<int,double> row1;
11 
12//編譯正常
13MyGenericCollection<int,System.Web.UI.WebControls.Label> row1;

New 條件約束
有時候我們會使用泛用類別工廠,他使用傳遞進來之型別數的型別來建立一個執行個體;
為了確保傳進來的擁有一個建構函式,也確保不是 MustInherit 類別與介面。
1public class Factory<T> where T : new(){
2    T CreateInstance(){
3        T newInstance = new T();
4        ...
5        return  newInstance;
6    }
7}


限制參考型別或是數值型別的條件約束
若要將傳遞的型別參數必須是「參考型別」,則須加入 class 關鍵字;
若要將傳遞的型別參數必須是「實數型別」,則須加入 struct 關鍵字。
1public class MyClass<T> where T : class{
2    ...
3}
4 
5public class MyClass<T> where T : struct{
6    ...
7}
如何指定多個條件約束
1public class MyClass<T>
2where T : class,IComparable,IDisposable,new(){
3    ...
4}
利用型別參數的物件存取類別與條件約束類別的成員
01//這是一個使用者自訂介面
02interface IRun{
03    void A();
04    void B();
05}
06 
07//這是使用者自訂介面
08interface IMove{
09    void A();
10    void B();
11}
12 
13//使用者自訂類別
14class Car(){
15    public void E();
16}
17 
18// 自訂泛用類別
19class MyClass<T1,T2>
20    where T1 : Car,IRun,new()
21    where T2 : IRun,IMove,new(){
22     
23    void test(){
24        //建立一個型別為 T1 的物件
25        T1 obj1 = new T1();
26 
27        //T1擁有類別條件約束 Car,
28        //所以可以直接存取Car 的成員E
29        obj1.E();
30 
31        //T1 擁有介面條件約束 IRun,
32        //所以可以直接存取 IRun 的成員
33        obj1.A();
34 
35        //建立一個型別為 T2  物件
36        T2 obj2 = new T2();
37 
38        //編譯錯誤,由於介面 IRun 與 IMove
39        //都擁有一個名稱為 A 的成員,所以
40        //這樣用會造成錯誤
41        obj2.A();
42 
43        //若要避免錯誤,須轉型
44        ((IRun)obj2).A();
45    }
46}
型別參數的多載
01pubic class MyCollection{
02 
03}
04 
05public class MyCollection<T1>{
06    static void Test(MyCollection<T1> arg){
07         
08    }
09    ...
10}
11 
12pubic class MyColleciton<T1,T2>{
13    public static void Show(MyColleciton<T1,T2>[] args){
14 
15    }
16    ...
17}
18 
19MyCollection o1;
20 
21MyCollection<int> o2;
22 
23MyCollection<int,string> o3;
24 
25//參考 2 個型別參數
26MyCollection<int,DateTime>.Show(null);

定義不同型別參數來多載泛用方法
1public class MyClass{
2    static int Compare<T>(T arg1,T arg2){
3    }
4    sataic int Compare<T1,T2>(T1 arg2,T2 arg2){
5    }
6}
7...
8MyClass.Compare<int>(1,2);
9MyClass.Compare<int,string>(10,"test");

沒有留言:

張貼留言