天天看點

泛型

.Net自從2.0版本開始就支援泛型。使用泛型類型可以最大限度地重用代碼、保護類型的安全以及提高性能。

性能

var list = new ArrayList();
            list.Add(20);//裝箱--将值類型轉換為引用類型

            int num = (int)list[0];//拆箱--将引用類型轉換為值類型

            foreach (int i in list)//拆箱
            {
                Console.WriteLine(i);
            }      

ArrayList存儲對象,是以Add方法會進行裝箱操作,當讀取ArrayList中的值時,需要将其轉換為int類型,需要進行拆箱操作。裝箱、拆箱操作很容易使用,但是性能損失較大,特别是周遊許多項時。

此時,我們可以使用List<T>泛型類來減少裝箱和拆箱操作,類型參數T定義為int類型

var list = new List<int>();
            list.Add(20);//不進行裝箱操作

            int num = list[0];//不進行拆箱操作

            foreach (int i in list)//不進行拆箱操作
            {
                Console.WriteLine(i);
            }      

類型安全

1             var list = new ArrayList();
2             list.Add(20);
3             list.Add("abc");
4             foreach (int i in list)//集合中并非所有元素都可以強制轉化為int類型,會出現一個運作異常
5             {
6                 Console.WriteLine(i);
7             }      

泛型類List<T>中,參數類型T可以定義允許使用的資料類型

1             var list = new List<int>();//參數類型T設定為int類型,隻允許對int類型的數值進行操作
2             list.Add(20);
3             list.Add("abc");//傳入參數資料類型與設定的參數類型不符,會導緻錯誤      

代碼複用性

我們看如下代碼,為了實作對不同資料類型的數組進行周遊,我們需要為每種類型都編寫一個方法:

1     class Generic
 2     {
 3         public void Main()
 4         {
 5             int[] arr_int = { 1, 2, 3 };
 6             string[] arr_string = { "abc", "123" };
 7             char[] arr_char = { 'a', 'b', 'c' };
 8             PrintArray(arr_int);
 9             PrintArray(arr_string);
10             PrintArray(arr_char);
11 
12             Console.ReadKey();
13         }
14         //周遊int類型的數組
15         void PrintArray(int[] arr)
16         {
17             foreach (int i in arr)
18             {
19                 Console.WriteLine(i);
20             }
21         }
22         //周遊string類型的數組
23         void PrintArray(string[] arr)
24         {
25             foreach (string str in arr)
26             {
27                 Console.WriteLine(str);
28             }
29         }
30         //周遊char類型的數組
31         void PrintArray(char[] arr)
32         {
33             foreach (char ch in arr)
34             {
35                 Console.WriteLine(ch);
36             }
37         }
38     }      

但是如果我們使用泛型的話,代碼就簡單多了

1     class Generic
 2     {
 3         public void Main()
 4         {
 5             int[] arr_int = { 1, 2, 3 };
 6             string[] arr_string = { "abc", "123" };
 7             char[] arr_char = { 'a', 'b', 'c' };
 8             //完整的寫法
 9             PrintArray<int>(arr_int);
10             PrintArray<string>(arr_string);
11             PrintArray<char>(arr_char);
12             //簡便寫法
13             PrintArray(arr_int);
14             PrintArray(arr_string);
15             PrintArray(arr_char);
16 
17             Console.ReadKey();
18         }
19         //周遊數組
20         void PrintArray<T>(T[] arr)
21         {
22             foreach (T item in arr)
23             {
24                 Console.WriteLine(item);
25             }
26         }
27     }      

命名約定

如果在程式中使用了泛型,遵循泛型的命名規則可以幫助我們區分泛型類型和非泛型類型。

泛型類型的命名規則:

  • 泛型類型的名稱用字母T作為字首;
1     class TClassName<T>
2     {
3         //...
4     }      
  • 如果沒有特殊的要求,泛型類型允許用任意的類型代替,并且隻使用了一個泛型類型,就可以用T作為泛型類型的名稱;
  • 如果泛型類型有特定的要求的(例如,他必須實作一個接口或派生自基類),或者使用了兩個或多個泛型類型,就應該為泛型類型使用描述性的名稱
1     class TClassName<TParam1, Tparam2>
2     {
3         //...
4     }      

泛型類的預設值

我們看下邊的代碼,我們需要将變量value進行初始化,要求如果value是引用類型就初始化為null,如果value是值類型就初始化為0;但是泛型中并不能确定T的類型是值類型或是引用類型,那我們要如何進行初始化呢?為了解決這個問題,我們可以是會用default關鍵字。default關鍵字會根據T的類型進行初始化,如果T為引用類型就将其設定為null,如果T為值類型就将其設定為0。

1         public T Test<T>()
2         {
3             T value = default(T);
4             //..Do Something
5             return value;
6         }      

 限制

限制 說明
where T:struct 指定類型T必須是值類型
where T:class 指定類型T必須是引用類型
where T:IFoo 指定類型T必須實作接口IFoo
where T:Foo 指定類型T必須派生自基類Foo
where T:new() 構造函數限制,指定類型T必須有一個預設的無參構造函數(構造函數隻能對無參的構造函數進行限制)
where T1:T2 類型T1派生自泛型類型T2