泛型的約束理解

風靈使發表於2018-09-12

1.引用型別約束

struct RefSample<T> where T:class 引用型別用Class表示約束,其他的引用型別為具體的約束。
表示對於的約束必須為一個類(引用型別)不能是值型別(int,char,datatime,struct),可以是介面interface

區分,陣列為引用型別,因為定義陣列時需要new出一個物件。
雖然定義成 RefSample<T> 傳入的必須為引用型別 但是RefSample仍然為值型別

2.值型別約束

class ValSample<T> where T:struct

為引用型別,因為intchar等型別都是struct
這裡寫圖片描述

ValSample<int>

3.建構函式型別約束

public T CreateInstance<T>() where T:new()
{
     return new T();
}

指定的型別T必須有建構函式,CreateInstance<int>CreateInstance<object> 都是有效的。但是CreateInstance<strings>沒有建構函式。

4.轉換型別約束

一種約束允許你指定另一個型別,型別實參必須可以通過一致性、引用或裝箱轉換隱式地轉換為該型別。你還可以規定一個型別實參必須可以轉換為另一個型別實參——這稱為型別引數約束。
理解的意思:可以互換,就是我們可以通過裝箱或者強制型別轉換成目標型別的 型別都可以用於型別引數傳入。

class Sample<T> where T:Stream

有效:Sample<Stream> 這本身符合約束
無效:Sample<String> 因為String型別無法通過引用或者裝箱拆箱強制轉換成Stream、

struct Sample<T> where T:IDisposable

規定T必須為IDisposable 型別的 引用型別
有效:Sample<SqlConnection>引用轉換
無效:Sample<StringBuilder>
分析:為什麼SqlConnection 可以而StringBuilder不可以?它們都是引用型別
1.SqlConnection實現了IDisposable介面,所以可以協變
這裡寫圖片描述

這裡寫圖片描述
2.StringBuilder只實現了ISerializable介面,無法通過途徑轉換為IDisposable
這裡寫圖片描述

class Sample<T> where T:IComparable<T>

因為將IComparable<T>整體當作約束,分析IComparable<T>的型別,可以用Type.IsValueType判斷,true為值型別,false為引用型別
typeof(IComparable<T>).IsValueType 結果為false表示為引用型別

有效:Sample<int>(裝箱轉換)
無效:Sample<FileInfo>

也可以指定多種約束:

class sample<T> where TstreamIEnumerable<string>,IComparable<int>
class Sample<T,U> where T:U

有效:Sample<Stream,IDisposable>
無效:Sample<string,IDiposable>
總結:要看傳入類引數是否可以轉換,檢視規定引數和傳入類引數是否實現同一介面,如果實現則可以,否則不可以。
不可以是以下:System.Object,System.Enum,System.ValueType,System.Delegate,結構或密封類(String)

5.組合約束

對型別引數的約束有多個,注意:只能是一種型別,值型別和引用型別不能同時存在,沒用一個型別即是引用型別,又是值型別。
由於每一個值型別都有一個無建構函式,此後不能再有建構函式約束
有效:

class Sample<T> where TclassIDisposablenew()
class Sample<T,U> where TStream where U:IDispsable

無效:
class Sample<T> where T:class,struct (沒有任何型別即時引用型別又是值型別的,所以為無效的)
class Sample<T> where T:Stream,class (引用型別約束應該為第一個約束,放在最前面,所以為無效的) Stream只是約束傳入引數為Stream具體型別,而class約束為引用型別,一開始我理解錯了
class Sample<T> where T:new(),Stream (new() 必須放在最後)
class Sample<T> where T:IDisposable,Stream (類必須放在介面前面,所以為無效的)
class Sample<T> where T:XmlReader,IComparable,IComparable (對於轉換型別約束,同一個介面不能出現多次)
class Sample<T,U> where T:struct where U:Class,T (型別形參“T”具有“struct”約束,因此“T”不能用作“U”的約束,所以為無效的)
class Sample<T,U> where T:Stream ,U:IDisposable 語法錯誤

看到網上還有這種版本也是有效的我表示不理解:
class Sample<T> where T:struct,IDisapsable IDisapsable為值型別?
class Sample<T,U> where T:class where U:struct ,T T為引用型別為何與值型別一起約束U
希望可以指正

相關文章