1. 程式人生 > 實用技巧 >探討c#中的泛型、委託、泛型委託、Action和Func及使用場景系列之一:泛型

探討c#中的泛型、委託、泛型委託、Action和Func及使用場景系列之一:泛型

本系列將分別介紹泛型和委託的概念,比較泛型和委託在使用場景上的本質不同點,

最後介紹泛型委託結合起來如何使用及.net自身提供的兩個泛型委託Action和Func。

-------------------------------------------------------------------分隔符----------------------------------------------------------------------------

泛型是C#2.0中推出的功能,目的是解決型別強制轉換的效率和風險問題,泛型可以作用於介面、類、方法、事件和委託,

在使用泛型前,我們先看泛型是如何引入的,考慮下面的開發場景:向一個集合中新增元素,然後遍歷輸出元素,程式碼如下:

 1     public class Class1
 2     {
 3         public void Test()
 4         {
 5             ArrayList list = new ArrayList();
 6             list.Add("aaa");
 7             list.Add("bbb");
 8 
 9             for(int i=0;i<list.Count;i++)
10             {
11                 string str = (string
)list[i]; 12 } 13 } 14 15 }

因為ArrayList中的元素是object 型別的,所以用Add( )方法新增元素的時候有一個裝箱(Boxing)的過程,

這樣在遍歷使用的時候需要做拆箱(UnBoxing)的操作,即強制將object轉化成string型別後再使用。

在裝箱和拆箱的過程中就會損失效能和效率,而且弱型別對程式設計不友好,會帶來意外的風險,換成泛型集合後代碼如下:

 1         public void Test2()
 2         {
 3             List<string
> list2 = new List<string>(); 4 list2.Add("aaa"); 5 list2.Add("bbb"); 6 7 for (int i = 0; i < list2.Count; i++) 8 { 9 string str = list2[i]; 10 } 11 }

宣告集合類的時候就指明該集合中的元素只能接收字串List<string>( ) ,遍歷的時候也無需強制轉換。

場景二 : 根據傳入的值比較大小並返回較大的那個值

 1     public class Class1
 2     {
 3         private int x1, y1;
 4         public Class1(int x, int y)
 5         {
 6             this.x1 = x;
 7             this.y1 = y;
 8         }
 9         public int GetBigger()
10         {
11             return x1 > y1 ? x1 : y1;
12         }
13          
14     }
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         { 
 5 
 6             Class1 c1 = new Class1(3, 5);
 7             int i = c1.GetBigger();
 8             Console.WriteLine(i);
 9 10 
11             Console.ReadLine();
12         }
13     }

如果我們要比較兩個浮點數的大小,Class1是不能複用的,必須再寫Class2來滿足這樣的需求,

可以預見,Class1和Class2除了型別不同,程式碼幾乎一模一樣,

這裡該泛型類上場了,泛型特性提供了一種更優雅的方式,讓多個型別共享一組程式碼,

我們用泛型來改造Class1,將Class2寫成一個泛型類,如下:

 1     public class Class2<T> where T: IComparable 
 2     {
 3         private T x1, y1;
 4         public Class2(T x, T y)
 5         {
 6             this.x1 = x;
 7             this.y1 = y;
 8         }
 9         public T GetBigger()
10         {
11             return x1.CompareTo(y1)>0 ? x1 : y1;
12         }
13     }

在Class2中,我們在類名Class2後加了“<T>”這樣一個泛型標記,T是一個型別佔位符,用尖括號括起來放在類名後面,

有了這個聲明後在這個類的內部就可以使用這個型別," where T: IComparable " 為泛型約束,它告訴外部的呼叫者,

傳入的型別必須實現IComparable這個介面,否則編譯器就會報錯。因為型別 T 實現了IComparable介面,

所以GetBigger()方法中可以呼叫型別的CompareTo()方法來比較兩個數的大小(c#中所有的數值型別都實現了IComparable介面)。

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         { 
 5 
 6             Class1 c1 = new Class1(3, 5);
 7             int i = c1.GetBigger();
 8             Console.WriteLine(i);
 9 
10 
11             Class2<double> c2 = new Class2<double>(3.5, 5.2);
12             double i2 = c2.GetBigger();
13             Console.WriteLine(i2);
14 
15 
16             Console.ReadLine();
17         }
18     }

在呼叫的時候,可以明顯看到Class1和Class2構造的不同,Class2後面多了" <double> " 這樣一個泛型宣告,

所以Class2建構函式傳入的數必須是double型的,如果我們要比較整型數的大小,就可以直接用Class2這個泛型類了,

程式碼如下(紅色部分) :

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         { 
 5 
 6             Class1 c1 = new Class1(3,5);
 7             int i = c1.GetBigger();
 8             Console.WriteLine(i);
 9 
10 
11             Class2<double> c2 = new Class2<double>(3.5, 5.2);
12             double i2 = c2.GetBigger();
13             Console.WriteLine(i2);
14 
15 
16             Class2<int> c22 = new Class2<int>(99, 87);
17             int i22 = c22.GetBigger();
18             Console.WriteLine(i22);
19 
20 
21             Console.ReadLine();
22         }
23     }

只需在宣告的時候傳入int 型別就可以了,這樣程式碼寫起來就舒服多了。

--------------------------------------------------------------------分隔符---------------------------------------------------------------------------------

接下來我們看泛型方法的使用 :

明白了泛型類的使用,泛型方法的使用是類似的,定義泛型方法只需要在方法名後加上 "<T>"就可以了,如果有兩個泛型型別,

就用逗號分隔兩個泛型識別符號,如 "<T1, T2>",多個泛型型別以此類推,我們將上面比較大小的功能用泛型方法來實現,程式碼如下:

1     public class Class3
2     {
3         public T GetBigger<T>(T x1, T y1) where T:IComparable
4         {
5             return    x1.CompareTo(y1) > 0 ? x1 : y1;
6         }
7     }

方法名GetBigger和方法引數之間加上泛型標記 "<T>" ,因為是比較兩個數的大小,所以要對型別T用where做一下約束,

型別T必須實現IComparable介面(這個介面只有一個CompareTo( )方法), 這樣型別變數 x1 才能呼叫CompareTo( ) 方法來比較大小。

呼叫的方式如下(見紅色程式碼部分):

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         { 
 5 
 6             Class1 c1 = new Class1(3,5);
 7             int i = c1.GetBigger();
 8             Console.WriteLine(i);
 9 
10 
11             Class2<double> c2 = new Class2<double>(3.5, 5.2);
12             double i2 = c2.GetBigger();
13             Console.WriteLine(i2);
14 
15 
16             Class2<int> c22 = new Class2<int>(99, 87);
17             int i22 = c22.GetBigger();
18             Console.WriteLine(i22);
19 
20 
21             Class3 c3 = new Class3();
22             int i3 = c3.GetBigger<int>(82, 37);
23             Console.WriteLine(i3);
24 
25 
26             Console.ReadLine();
27         }
28     }

接下來一篇將介紹c#中的委託。