.NET泛型解析(下)
上一篇對.NET中的泛型進行了詳細的介紹以及使用泛型的好處是什么,這篇將更加深入的去了解泛型的其他的知識點,重頭戲.
【1】泛型方法
上一篇我們也說過了,泛型可以是類,結構,接口,在這些泛型類型中定義的方法都可以叫做泛型方法,都可以引用由泛型類型本身指定的一個類型參數例如:1 public class GenericType<T> 2 { 3 4 private T G_Value; 5 6 public T Convert<T> { T res = (T)Convert.ChangeType(G_value,typeof(T)); return res; } 7 8 }泛型方法的存在為我們提供了極大的靈活性。 泛型方法顧名思義,首先它是一個方法,只不過這個方法的返回值,參數可能是泛型的, 類型推斷 類型推斷就是根據泛型方法中定義的形參類型T,在我們調用的使用,那么所要傳的也應該是一致的。例如:
1 static void Test<T >(ref T t1,ref T t2) 2 { 3 T temp = t1; 4 t1 = t2; 5 t2 = temp; 6 }
這是我們定義的一個泛型方法,第一個參數類型為 T,第二個也為 T,說明這兩個類型是一致的。那么我們在調用的時候應該這樣 :
1 int i = 8, j = 0 ; 2 3 Test( ref i, ref j);
而如果我們兩個實參的類型不統一的話,那么就會引發編譯異常例如 :
開放類型和封閉類型
具有泛型類型參數的類型對象讓就還是一個類型, CLR內部依舊和其他的對象類型一樣創建一個內部類型對象, 那么這種具有泛型類型參數的類型稱之為開放類型,開發類型不能進行構造任何的實例. 當泛型類型參數是一個實參時,那么所有的類型實參傳遞的都是實際的數據類型了,這種類型稱之為 封閉類型,封閉類型是允許構造實例對象的1 class DictionaryStringKey <T> : IEnumerable<T> 2 { 3 public IEnumerator<T> GetEnumerator() 4 { 5 throw new NotImplementedException(); 6 } 7 8 System .Collections. IEnumerator System. Collections.IEnumerable .GetEnumerator() 9 { 10 throw new NotImplementedException(); 11 } 12 }View Code
在上述代碼中,有一個DictionaryStringKey的類,繼承了一個IEnumable<T>的泛型,那么根據我們的開放類型它在調用的時候是不只是具體的實參,并且不能被構造實例的.
1 static void Main( string[] args) 2 { 3 object o = null; 4 Type t = typeof( DictionaryStringKey <>); 5 o = CreateInstance(t); 6 Console .ReadLine(); 7 8 } 9 10 private static object CreateInstance( Type t) 11 { 12 object o = null; 13 try 14 { 15 o = Activator . CreateInstance(t); 16 Console .WriteLine( @" 創建了 " + t + "的實例 " , t .ToString()); 17 } 18 catch (Exception ex) 19 { 20 o = Activator . CreateInstance(t); 21 Console .WriteLine( @" 創建 " + t + "的實例失敗 " , t .ToString()); 22 } 23 24 return o; 25 }View Code
上述代碼中我嘗試著對開放類型進行實例化,結果報出異常 :
當我們傳入實參之后,那么它就是一個封閉類型,這樣我們就可以進行構造實例了.
1 static void Main( string[] args) 2 { 3 object o = null; 4 Type t = typeof( DictionaryStringKey <string > ); 5 o = CreateInstance(t); 6 Console .ReadLine(); 7 8 }View Code
?【2】泛型接口
泛型的主要作用就是定義泛型的引用類型和值類型,在CLR中,對于泛型接口的支持也是很重要的,因為這樣更有益與程序的擴展性, 另外一點如果沒有泛型接口我們每次使用非泛型接口時都會進行裝箱操作(例如: ?IComparable),并且會失去編譯時的安全性(因為它是非泛型的,較之泛型的好處之一).
那么CLR提供了對于泛型接口的支持,對于引用類型和值類型可以通過制定實參的方式來實現泛型接口,同時也可以保持未指定狀態來實現一個泛型接口( 接受者也可以是泛型 , 可以在后期進行指定類型)
實例 1 : 聲明一個泛型接口
1 interface IPair <T> 2 { 3 T First { get; set ; } 4 T Second { get; set ; } 5 }IPair這個接口實現了一對相關的對象,兩個數據項具有相同的類型. 實現接口時,語法與非泛型類的語法是相同的,如果在實現泛型接口時,同時不指定實參,則默認為是一個泛型類. 實例 2 : 泛型接口的實現
1 class Pair <T> : IPiar< T> 2 { 3 public T First 4 { 5 get 6 { 7 throw new NotImplementedException(); 8 } 9 set 10 { 11 throw new NotImplementedException(); 12 } 13 } 14 15 public T Second 16 { 17 get 18 { 19 throw new NotImplementedException(); 20 } 21 set 22 { 23 throw new NotImplementedException(); 24 } 25 } 26 }View Code
CLR泛型接口的支持對于集合類型來講尤其重要,同時泛型在集合類型中較為常用,如果沒有泛型那么我們所使用List的時候都要依賴與System.Collections,我們在每次訪問的時候都需要執行一次轉換,如果使用泛型接口,就可以避免執行轉型,因為參數化的接口能實現更強的編譯時綁定.
實例 3 :?在一個類中多次實現相同的接口
1 interface IContainer <T> 2 { 3 ICollection<T > Items { get ; set; } 4 } 5 6 public class Person : IContainer<A >,IContainer <B> 7 { 8 9 public ICollection <A> Items 10 { 11 get 12 { 13 throw new NotImplementedException(); 14 } 15 set 16 { 17 throw new NotImplementedException(); 18 } 19 } 20 21 ICollection<B > IContainer <B>. Items 22 { 23 get 24 { 25 throw new NotImplementedException(); 26 } 27 set 28 { 29 throw new NotImplementedException(); 30 } 31 } 32 }View Code
Items屬性使用一個顯式接口實現多次出現,每一次,類型參數都有所不同,如果沒有泛型,這是做不到的,在非泛型的情況下,CLR只允許一個顯式的IContainer.Items屬性.
【4】泛型約束(主要約束,次要約束,構造器約束)
約束也可以理解為是一種規則,意思就是我們所編寫的所有泛型,你在調用的時候,應該給我傳輸那些類型的實參。
在上一篇中,我們也在一個DataTableToList中使用到了約束,但是并沒有進行講解,在這里我們詳細的說明一下: 在.NET 中有4中約束方式,它們的常規語法是相同的,約束要放在泛型方法或者泛型類型聲明的末尾,并由上下文關鍵字 ”where :“ ?來引入 。 主要約束(引用類型約束): 主要約束表示的是 : 我們在指定一個引用類型約束時,那么一個指定的類型實參要么是與約束類型相同的類型,要么是從約束類型派生的一個類型 實例 4 : 引用類型約束1 struct Generic<T>(T t1) where : class這里我定義了一個泛型方法,Generic,后來寫了一個where : class,這就告訴編譯器,在使用者調用這個方法時,必須為這個方法的傳入一個引用類型的實參,同時,我們也可以注意到這個方法的返回類型為struct值類型。 主要約束(值類型約束) 很明顯,值類型約束的話,就是將 約束條件指定為 Struct 實例 5 : 值類型約束
1 class ConstraintOfStruct <T> where T : struct 2 { 3 public T result() 4 { 5 return new T(); 6 } 7 }
在代碼中,我們最后返回的是new T(),這個是沒有問題的,因為我們已經可以肯定T就是值類型,所有的值類型都有一個隱式的構造函數,那么如果我們將 約束條件改為 class的話,那么就會出異常,因為不是所有的引用類型都可以實例化.
實例 6 : 反面教材 - 約束為引用類型時進行實例化.
構造函數類型約束 構造函數類型約束表示為 T : new(),這個約束必須為所有的類型參數的最后一個約束,它用于檢查類型實參是否有一個可用于創建類型實例的無參構造函數,這一點比較適用于所有的值類型,所有的沒有顯式聲明構造函數的非靜態、非抽象類,所有顯式聲明了一個公共無參構造函數的非抽象類。 實例 7 : 構造函數類型約束1 public T CreateInatance<T >() where T : new() 2 { 3 return new T(); 4 }
在方法createInstance中,要求我們必須傳入一個無參的構造函數,例如:我們可以傳入 object,struct,stream等,但是不能傳入 string,Directory等.
接口約束:
接口約束的一個好處就是我們可以指定多個接口,但是只能指定一個類1 class ConstraintOfStruct <T> where T : class,IEquatable <T> ,IComparable<T> 2 { 3 }組合約束 : 組合約束就是指定多個約束條件在上一個約束中我們已經看到了 ,更詳細的如下 :
1 class Sample<T> where T : class ,IDisposable,new(){} 2 class Sample<T> where T : struct,IDisposable{} 3 class Sample<T,U> where T : Stream where U : IDisposable{} 4 5 class Sample<T> where T : class ,structView Code
【5】泛型類型轉型??
1 public static T Desercialies <T > (Stream stream, IFormatter formatter) 2 { 3 return (T)formatter. Deserialize(stream); 4 }
formatter 負責將流轉換為 Object,返回一個Object類型,我們在使用泛型調用的時候應該這樣來 :
1 string result = Desercialies <string > (stream, formatter);
上述的代碼看著是一種強制轉換,但是仍然執行了隱式的轉換,就和使用非泛型?string?result?=?(string)Desercialies(stream, formatter); 一樣
【6】泛型和屬性
?屬性也可以應用到泛型類型中,使用的方式和非泛型類型相同.自定義的屬性只允許引用開發泛型類型
1 class MyClass<T,S> where T :class 2 where S : struct 3 { 4 public T MyName { get; set; } 5 public S MyCode { get; set; } 6 public List<T> MyCourse { get; set; } 7 public List<S> MyStudyHistory { get; set; } 8 }
上述我們定義了一個MyClass?類,這個類有兩個參數一個是引用類型一個是值類型.在屬性MyName,MyCourse的類型都是引用類型,MyCode的類型都為值類型
泛型類型構造器:
1 class Pair < T> : IPiar< T > 2 { 3 private T _first; 4 5 public T First 6 { 7 get { return _first; } 8 set { _first = value; } 9 } 10 private T _second; 11 12 public T Second 13 { 14 get { return _second; } 15 set { _second = value; } 16 } 17 public Pair(T first,T second) 18 { 19 20 } 21 } 22 interface IPiar < T> { }View Code
泛型的構造器不需要添加類型參數來與類的聲明一致.
?
先到這里, 下一篇著重分享協變和逆變,否則這一篇符太長,不利于以后的查看.
泛型委托和泛型反射留在深入總結委托和反射的時候進行總結。
同時,希望給在閱讀的你帶來一些幫助。
轉載于:https://www.cnblogs.com/DeepLearing/p/4564791.html
總結
以上是生活随笔為你收集整理的.NET泛型解析(下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 亲们有没有遇到这样的事情过,我表示好郁闷
- 下一篇: 制作显示欢迎信息的脚本程序