天天看點

跟小靜讀CLR via C#(16)--泛型

泛型就像是一個模闆,常常定義一些通用的算法,具體調用時再替換成實際的資料類型,提高了代碼的可重用性。

以最常用的FCL中的泛型List<T >為例:

static void Main(string[] args)        {            List<int> num = new List<int>();            num.Add(1);            num.Add(3);            int num1 = num[0];            int num2 = num[1];        }

尖括号中的T是不确定的資料類型,叫做類型參數,一般規定以字母T開頭,可以是TKey, TValue都可以。而調用時指定的具體類型叫做類型實參。

檢視一下IL代碼:

類型名List是以“`”加數字結尾的。數字表示類型的元數,也就是需要指定具體類型的參數個數。

泛型是類型安全的。如果用“num.Add("a");”會發生編譯錯誤;

泛型可以提高算法的可重用性,而且從例子中看出int類型并沒有進行裝箱拆箱操作,相比将所有類型轉換為Object的方式而言,提高了程式的性能。

為泛型變量設定預設值時常使用default關鍵字進行,T temp=default(T)。如果T為引用類型,則temp為null;如果T為值類型,則temp設為0值.

開放類型:具有泛型參數的類型是開放類型,如List<T>,CLR不允許構造開放類型的執行個體;

封閉類型:在實際調用代碼時,如果所有類型實參都已經指定了實際資料類型,如List<string>,則該類型為封閉類型。CLR允許構造封閉類型的執行個體。

先看這段很常見的代碼:

為了增強可讀性,編譯器支援類型推斷功能,省略<>,我們可以将上面調用的方法改為:

<a href="http://images.cnblogs.com/cnblogs_com/janes/201112/201112211601203908.png"></a>

* 需要注意的是,類型推斷時C#使用的是變量的資料類型,而不是變量引用的對象的類型。例如:

<a href="http://images.cnblogs.com/cnblogs_com/janes/201112/201112211601368383.png"></a> 雖然s1和s2都是指向了字元串對象,但是這兩個變量的類型是不同的,是以會産生編譯錯誤。

通過協變量和逆變量,可以将泛型委托或者接口的類型參數進行一定的類型轉換。

逆變量:泛型類型參數可以從基類轉為派生類,用in關鍵字辨別,隻出現在輸入位置,例如方法的參數;

public delegate void Func&lt;in T&gt;(T arg); { Func&lt;object&gt; f1 = null; Func&lt;string&gt; f2 = f1; }

協變量:泛型類型參數可以從派生類改為它的基類,用out關鍵字辨別,隻出現在輸出位置,例如方法的傳回值。

public delegate TResult Func&lt;out TResult&gt;(); Func&lt;string&gt; fn=null; object result=fn();

在設計泛型的類型參數時,可以通過where子句指定類型需要滿足的限制條件。主要包含以下幾種限制方式:

一個類型參數可以指定0或1個主要限制,主要限制可以一個非密封的引用類型,它表示類型實參必須與限制類型相同或者為限制類型的派生類。該引用類型不能為Object, Array, Delegate, MulticastDelegate, ValueType, Enum, Void。

class Constraint1&lt;T&gt; where T : Stream      public void Close(T stream)      {          stream.Close();      } class Program      static void Main(string[] args)          Constraint1&lt;FileStream&gt; s2 = new Constraint1&lt;FileStream&gt;();

兩種特殊的主要限制:class和struct。

Class限制:要求指定的類型實參必須是引用類型。Where T:class

在沒有限制的情況下,如果T為值類型,是不能指派為null的,是以會産生編譯錯誤。添加限制後編譯通過:

<a href="http://images.cnblogs.com/cnblogs_com/janes/201112/201112211601383216.png"></a>

Struct 限制:要求指定的類型實參必須是值類型

在沒有限制的情況下,如果T為引用類型是不能聲明為可空值類型的,是以會産生編譯錯誤。添加struct限制後運作正常:

一個類型參數可以指定0或者多個次要限制。常見的次要限制主要有兩種:

接口限制:類型實參必須實作了指定的所有接口。例如:

接口限制的另外一個好處是:值類型實參調用接口方法時不用進行裝箱操作。

類型參數限制:在指定的類型實參之間,存在着一定關系。例如要求存在繼承關系:

構造器限制要求類型實參必須實作了無參構造器,而且它不支援有參構造器。

    本文轉自 陳敬(Cathy) 部落格園部落格,原文連結: http://www.cnblogs.com/janes/archive/2011/12/21/2295959.html ,如需轉載請自行聯系原作者

繼續閱讀