C#之使類型參數--泛型


1、泛型是什么

泛型的就是“通用類型”,它可以代替任何的數據類型,使類型參數化,從而達到只實現一個方法就可以操作多種數據類型的目的。

2、為什么使用泛型

舉一個比較兩個數大小的例子:

以上例子實現int類型數據的大小比較是完全沒有問題的,但是如果客戶現在增加需求“又可以實現兩個字符串大小的比較”,此時就不得不在類中再添加一個比較字符串大小的方法了:

如果客戶現在還增加需求,要求實現浮點型的比較,那么工作量就更大了,不得不再次修改代碼,顯然這不是我們想看到的,兩個方法中有大部分代碼是類似的,所以微軟提出了一個激動人心的特性--泛型,他使得類型可以被參數化。

where語句是類型參數的約束它用來使參數可以適用於CompareTo方法。

向泛型中加入元素的效率遠比非泛型數組高,原因是非泛型rrayList的Add(Object value)方法中,參數為object類型,當把int參數i傳入方法時,會發生裝箱操作,從而導致性能的損失,使運行的時間變得更長。

泛型可以保證類型安全,當你向int類型數組中添加string類型的值的時候,會造成“無法從string類型轉換為int類型”的錯誤,因為你用int類型初始化了泛型類型。

3、泛型參數解析

1、類型參數

根據泛型類型參數是否已經提供實際類型,可分為未綁定的泛型和已構造的泛型,如果沒有給泛型提供實際類型,此時的泛型成為未綁定的泛型;如果已指定了實際類型作為參數,此時的泛型成為已構造泛型。

已構造泛型又稱為開放泛型和密封泛型。開放泛型指包含類型參數的泛型,所有未綁定的類型都屬於開放類型;而封閉類型指已經為每個參數都指定了實際數據類型的泛型。

2、泛型中的靜態字段和靜態函數問題

對於非泛型類,定義了一個靜態字段,不管是創建了多少個該類的實例,也不管從該類派生出多少個實例,都只存在一個字段,但是每個封閉的泛型類型中都有僅屬於他自己的靜態字段。

這是因為,在使用實際類型參數代替泛型參數時,編譯器會根據不同的類型參數,從新生成類型。

對於靜態構造函數,道理也是如此,每個封閉的泛型類型都有一個靜態構造函數,這里就不一一演示。

3、類型參數的推斷

寫泛型的時候可以省略掉“<>”,具體實際類型交由編譯器自行推斷。

編譯器會根據傳入實參的類型判斷實際類型參數。

4、類型參數的約束

(1)引用類型約束

表示形式:T:class;

以上代碼中,where T:Stream告訴編譯器:傳入的類型實參必須是System.IO.Stream,或者是從Stream派生出的一個類型。

如果一個類型參數沒有指定約束,那么默認T為System.Object類型。但若在代碼中顯式指定了System.Object約束,則編譯器會報錯:約束不能是特殊類Object。

(2)值類型約束

表現形式:T:struct

它確保傳遞的類型實參是值類型(包含枚舉),但這里的值類型不包括可空類型。

所有的值類型都有一個公共的無參構造函數,因此new T()是沒有問題的,但是引用類型沒有公共的無參構造函數,如果不對T進行約束,或約束為引用類型,則上邊代碼就會報錯。

(3)構造函數類型約束

表現形式:T:new();

如果類型參數有多個約束,則次約束必須最后指定,構造函數類型約束確保制定的類型有一個公共無參的構造函數的非抽象類型。

(4)轉換類型約束

表現形式:T:基類名、T:接口名或T:U

T:基類名確保制定的類型實參必須是基類或派生自基類的子類;

T:接口名確保制定的類型實參必須會接口或已經實現接口的類;

T:U確保T提供的是后面的類型實參或后面類型實參子類;

(5)組合約束

不同種類的約束合並到一起的約束,這里需要注意,沒有任何一種類型既是引用類型,又是值類型,這兩種約束不能同時使用。如果同時存在多個轉換類型約束,其中有一個是類,那么類必須放在接口前面。不同的類型參數有不同的約束,但是每種類型參數必須使用單獨的where關鍵字分開:

當然,C#中泛型的知識還有很多的應用場景,有興趣的可以去找一些書籍看看,收獲肯定不少,這里介紹只是讓大家有一個比較直觀的認識,看完后能夠對泛型有一個比較直觀的了解,懂得它有什么用,以及怎么去使用就行,更加高級的應用場景往后會慢慢分享,謝謝大家支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM