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

2012110611:10

出處:http://www.dotblogs.com.tw/atowngit/archive/2011/03/09/21758.aspx

條件約束有三種:型別條件約束、New 條件約束、限制參考型別或是數值型別的條件約束

 

型別條件約束

若是需要限制某個型別參數是繼承某一個類別或是實作一或多個介面。

01 public class MyGenericCollection
02 <KeyType,ElementType>
03 where KeyType : IComparable
04 where ElementType : System.Web.UI.WebControls.WebControl
05 {
06     ...
07 }
08   
09 //編譯發生錯誤
10 MyGenericCollection<int,double> row1;
11   
12 //編譯正常
13 MyGenericCollection<int,System.Web.UI.WebControls.Label> row1;

 

New 條件約束

有時候我們會使用泛用類別工廠,他使用傳遞進來之型別數的型別來建立一個執行個體;

為了確保傳進來的擁有一個建構函式,也確保不是 MustInherit 類別與介面。

1 public class Factory<T> where T : new(){
2     T CreateInstance(){
3         T newInstance = new T();
4         ...
5         return  newInstance;
6     }
7 }

 

 

限制參考型別或是數值型別的條件約束

若要將傳遞的型別參數必須是「參考型別」,則須加入 class 關鍵字;

若要將傳遞的型別參數必須是「實數型別」,則須加入 struct 關鍵字。

1 public class MyClass<T> where T : class{
2     ...
3 }
4   
5 public class MyClass<T> where T : struct{
6     ...
7 }

如何指定多個條件約束

1 public class MyClass<T>
2 where T : class,IComparable,IDisposable,new(){
3     ...
4 }

利用型別參數的物件存取類別與條件約束類別的成員

01 //這是一個使用者自訂介面
02 interface IRun{
03     void A();
04     void B();
05 }
06   
07 //這是使用者自訂介面
08 interface IMove{
09     void A();
10     void B();
11 }
12   
13 //使用者自訂類別
14 class Car(){
15     public void E();
16 }
17   
18 // 自訂泛用類別
19 class 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 }

型別參數的多載

01 pubic class MyCollection{
02   
03 }
04   
05 public class MyCollection<T1>{
06     static void Test(MyCollection<T1> arg){
07           
08     }
09     ...
10 }
11   
12 pubic class MyColleciton<T1,T2>{
13     public static void Show(MyColleciton<T1,T2>[] args){
14   
15     }
16     ...
17 }
18   
19 MyCollection o1;
20   
21 MyCollection<int> o2;
22   
23 MyCollection<int,string> o3;
24   
25 //參考 2 個型別參數
26 MyCollection<int,DateTime>.Show(null);

 

定義不同型別參數來多載泛用方法

1 public 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 ...
8 MyClass.Compare<int>(1,2);
9 MyClass.Compare<int,string>(10,"test");