上一篇對.NET中的泛型進(jìn)行了詳細(xì)的介紹以及使用泛型的好處是什么,這篇將更加深入的去了解泛型的其他的知識點,重頭戲.
創(chuàng)新互聯(lián)從2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站制作、成都網(wǎng)站建設(shè)網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元平陽做網(wǎng)站,已為上家服務(wù),為平陽各地企業(yè)和個人服務(wù),聯(lián)系電話:13518219792上一篇我們也說過了,泛型可以是類,結(jié)構(gòu),接口,在這些泛型類型中定義的方法都可以叫做泛型方法,都可以引用由泛型類型本身指定的一個類型參數(shù)例如:
public class GenericType<T>
{
private T G_Value;
public T Convert<T> { T res = (T)Convert.ChangeType(G_value,typeof(T)); return res; }
}
泛型方法的存在為我們提供了極大的靈活性。
泛型方法顧名思義,首先它是一個方法,只不過這個方法的返回值,參數(shù)可能是泛型的,
類型推斷
類型推斷就是根據(jù)泛型方法中定義的形參類型T,在我們調(diào)用的使用,那么所要傳的也應(yīng)該是一致的。例如:
static void Test<T >(ref T t1,ref T t2)
{
T temp = t1;
t1 = t2;
t2 = temp;
}
這是我們定義的一個泛型方法,第一個參數(shù)類型為 T,第二個也為 T,說明這兩個類型是一致的。那么我們在調(diào)用的時候應(yīng)該這樣 :
int i = 8, j = 0 ; Test( ref i, ref j);
而如果我們兩個實參的類型不統(tǒng)一的話,那么就會引發(fā)編譯異常例如 :
開放類型和封閉類型
具有泛型類型參數(shù)的類型對象讓就還是一個類型, CLR內(nèi)部依舊和其他的對象類型一樣創(chuàng)建一個內(nèi)部類型對象, 那么這種具有泛型類型參數(shù)的類型稱之為開放類型,開發(fā)類型不能進(jìn)行構(gòu)造任何的實例.
當(dāng)泛型類型參數(shù)是一個實參時,那么所有的類型實參傳遞的都是實際的數(shù)據(jù)類型了,這種類型稱之為 封閉類型,封閉類型是允許構(gòu)造實例對象的
class DictionaryStringKey <T> : IEnumerable<T> { public IEnumerator<T> GetEnumerator() { throw new NotImplementedException(); } System .Collections. IEnumerator System. Collections.IEnumerable .GetEnumerator() { throw new NotImplementedException(); } }
在上述代碼中,有一個DictionaryStringKey的類,繼承了一個IEnumable<T>的泛型,那么根據(jù)我們的開放類型它在調(diào)用的時候是不只是具體的實參,并且不能被構(gòu)造實例的.
static void Main( string[] args) { object o = null; Type t = typeof( DictionaryStringKey <>); o = CreateInstance(t); Console .ReadLine(); } private static object CreateInstance( Type t) { object o = null; try { o = Activator . CreateInstance(t); Console .WriteLine( @" 創(chuàng)建了 " + t + "的實例 " , t .ToString()); } catch (Exception ex) { o = Activator . CreateInstance(t); Console .WriteLine( @" 創(chuàng)建 " + t + "的實例失敗 " , t .ToString()); } return o; }
上述代碼中我嘗試著對開放類型進(jìn)行實例化,結(jié)果報出異常 :
當(dāng)我們傳入實參之后,那么它就是一個封閉類型,這樣我們就可以進(jìn)行構(gòu)造實例了.
static void Main( string[] args) { object o = null; Type t = typeof( DictionaryStringKey <string > ); o = CreateInstance(t); Console .ReadLine(); }
泛型的主要作用就是定義泛型的引用類型和值類型,在CLR中,對于泛型接口的支持也是很重要的,因為這樣更有益與程序的擴(kuò)展性, 另外一點如果沒有泛型接口我們每次使用非泛型接口時都會進(jìn)行裝箱操作(例如: IComparable),并且會失去編譯時的安全性(因為它是非泛型的,較之泛型的好處之一).
那么CLR提供了對于泛型接口的支持,對于引用類型和值類型可以通過制定實參的方式來實現(xiàn)泛型接口,同時也可以保持未指定狀態(tài)來實現(xiàn)一個泛型接口( 接受者也可以是泛型 , 可以在后期進(jìn)行指定類型)
實例 1 : 聲明一個泛型接口
interface IPair <T> { T First { get; set ; } T Second { get; set ; } }
IPair這個接口實現(xiàn)了一對相關(guān)的對象,兩個數(shù)據(jù)項具有相同的類型.
實現(xiàn)接口時,語法與非泛型類的語法是相同的,如果在實現(xiàn)泛型接口時,同時不指定實參,則默認(rèn)為是一個泛型類.
實例 2 : 泛型接口的實現(xiàn)
class Pair <T> : IPiar< T> { public T First { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public T Second { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } }
CLR泛型接口的支持對于集合類型來講尤其重要,同時泛型在集合類型中較為常用,如果沒有泛型那么我們所使用List的時候都要依賴與System.Collections,我們在每次訪問的時候都需要執(zhí)行一次轉(zhuǎn)換,如果使用泛型接口,就可以避免執(zhí)行轉(zhuǎn)型,因為參數(shù)化的接口能實現(xiàn)更強的編譯時綁定.
實例 3 : 在一個類中多次實現(xiàn)相同的接口
interface IContainer <T> { ICollection<T > Items { get ; set; } } public class Person : IContainer<A >,IContainer <B> { public ICollection <A> Items { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } ICollection<B > IContainer <B>. Items { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } }
Items屬性使用一個顯式接口實現(xiàn)多次出現(xiàn),每一次,類型參數(shù)都有所不同,如果沒有泛型,這是做不到的,在非泛型的情況下,CLR只允許一個顯式的IContainer.Items屬性.
約束也可以理解為是一種規(guī)則,意思就是我們所編寫的所有泛型,你在調(diào)用的時候,應(yīng)該給我傳輸那些類型的實參。
在上一篇中,我們也在一個DataTableToList中使用到了約束,但是并沒有進(jìn)行講解,在這里我們詳細(xì)的說明一下:
在.NET 中有4中約束方式,它們的常規(guī)語法是相同的,約束要放在泛型方法或者泛型類型聲明的末尾,并由上下文關(guān)鍵字 ”where :“ 來引入 。
主要約束(引用類型約束):
主要約束表示的是 : 我們在指定一個引用類型約束時,那么一個指定的類型實參要么是與約束類型相同的類型,要么是從約束類型派生的一個類型
實例 4 : 引用類型約束
struct Generic<T>(T t1) where : class
這里我定義了一個泛型方法,Generic,后來寫了一個where : class,這就告訴編譯器,在使用者調(diào)用這個方法時,必須為這個方法的傳入一個引用類型的實參,同時,我們也可以注意到這個方法的返回類型為struct值類型。
主要約束(值類型約束)
很明顯,值類型約束的話,就是將 約束條件指定為 Struct
實例 5 : 值類型約束
class ConstraintOfStruct <T> where T : struct { public T result() { return new T(); } }
在代碼中,我們最后返回的是new T(),這個是沒有問題的,因為我們已經(jīng)可以肯定T就是值類型,所有的值類型都有一個隱式的構(gòu)造函數(shù),那么如果我們將 約束條件改為 class的話,那么就會出異常,因為不是所有的引用類型都可以實例化.
實例 6 : 反面教材 - 約束為引用類型時進(jìn)行實例化.
構(gòu)造函數(shù)類型約束
構(gòu)造函數(shù)類型約束表示為 T : new(),這個約束必須為所有的類型參數(shù)的最后一個約束,它用于檢查類型實參是否有一個可用于創(chuàng)建類型實例的無參構(gòu)造函數(shù),這一點比較適用于所有的值類型,所有的沒有顯式聲明構(gòu)造函數(shù)的非靜態(tài)、非抽象類,所有顯式聲明了一個公共無參構(gòu)造函數(shù)的非抽象類。
實例 7 : 構(gòu)造函數(shù)類型約束
public T CreateInatance<T >() where T : new()
{ return new T(); }
在方法createInstance中,要求我們必須傳入一個無參的構(gòu)造函數(shù),例如:我們可以傳入 object,struct,stream等,但是不能傳入 string,Directory等.
接口約束:
接口約束的一個好處就是我們可以指定多個接口,但是只能指定一個類
class ConstraintOfStruct <T> where T : class,IEquatable <T> ,IComparable<T>{}
組合約束 :
組合約束就是指定多個約束條件在上一個約束中我們已經(jīng)看到了 ,更詳細(xì)的如下 :
class Sample<T> where T : class ,IDisposable,new(){} class Sample<T> where T : struct,IDisposable{} class Sample<T,U> where T : Stream where U : IDisposable{} class Sample<T> where T : class ,struct
public static T Desercialies <T > (Stream stream, IFormatter formatter) { return (T)formatter. Deserialize(stream); }
formatter 負(fù)責(zé)將流轉(zhuǎn)換為 Object,返回一個Object類型,我們在使用泛型調(diào)用的時候應(yīng)該這樣來 :
string result = Desercialies <string > (stream, formatter);
上述的代碼看著是一種強制轉(zhuǎn)換,但是仍然執(zhí)行了隱式的轉(zhuǎn)換,就和使用非泛型 string result = (string)Desercialies(stream, formatter); 一樣
屬性也可以應(yīng)用到泛型類型中,使用的方式和非泛型類型相同.自定義的屬性只允許引用開發(fā)泛型類型
class MyClass<T,S> where T :class
where S : struct
{
public T MyName { get; set; }
public S MyCode { get; set; }
public List<T> MyCourse { get; set; }
public List<S> MyStudyHistory { get; set; }
}
上述我們定義了一個MyClass 類,這個類有兩個參數(shù)一個是引用類型一個是值類型.在屬性MyName,MyCourse的類型都是引用類型,MyCode的類型都為值類型
泛型類型構(gòu)造器:
class Pair < T> : IPiar< T >
{
private T _first;
public T First
{
get { return _first; }
set { _first = value; }
}
private T _second;
public T Second
{
get { return _second; }
set { _second = value; }
}
public Pair(T first,T second)
{
}
}
interface IPiar < T> { }
型的構(gòu)造器不需要添加類型參數(shù)來與類的聲明一致.
先到這里, 下一篇著重分享協(xié)變和逆變,否則這一篇符太長,不利于以后的查看.
泛型委托和泛型反射留在深入總結(jié)委托和反射的時候進(jìn)行總結(jié)。
如果你覺得本文對你有幫助的話,請點右下角的推薦,或者直接關(guān)注我,后續(xù)將不斷更新.NET解析這一系列的文章....
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
本文題目:.NET泛型解析(下)-創(chuàng)新互聯(lián)
當(dāng)前網(wǎng)址:http://aaarwkj.com/article30/hssso.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、網(wǎng)站改版、全網(wǎng)營銷推廣、ChatGPT、微信小程序、網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容