C# 泛型的型別約束
對於沒有型別約束的泛型,其型別引數可以指定為任意型別。
例如List<T>,其型別引數T是值型別(List<int>)或引用型別(List<objiect>)。
有時候,我們希望泛型的型別引數只能是值型別或引用型別,這時就該論到型別約束上場了。
約束要放到泛型方法或泛型型別宣告的末尾,並由關鍵字where來引入。
在C#中,有4中型別約束可供使用。
1、引用型別約束
這種約束用於確保使用的型別實參是應用型別。型別實參可以是任何類。介面。陣列。委託,或者已知是引用型別的另外一個型別引數。例如以下宣告:
class Sample<T> whereT : class
Sample<object>、Sample<int[]>等引用型別作為型別實參的是有效的。
Sample<int>、Sample<Color>等值型別作為型別實參的無效的。
2、值型別約束
這種約束用於確保使用的型別實參是值型別的,包括列舉、結構體等,但可空型別除外。例如以下宣告:
class Sample<T> where T : struct
Sample<int>、Sample<Color>等值型別作為型別實參的有效的。
Sample<object>、Sample<int[]>等引用型別作為型別實參的是無效的。
3、建構函式型別約束
建構函式型別約束表示為T:new(),如果有多個型別引數,必須是所有型別引數的最後一個引數。它檢測型別實參是否有一個可用於型別例項的無參構造體。這適用於所有值型別;所有沒有顯式宣告構造體的非靜態類、非抽象類;所有顯式聲明瞭一個無參建構函式的非抽象類。例項如下:
public T Create<T>() where T : new() { return new T(); }
Create<int>()、Create<object>()都是有效的,但是Create<string>是無效的,因為string沒有無參建構函式。
4、轉換型別約束
最後一種型別約束允許你指定另一種型別,型別實參必須可以通過一致性、引用或裝箱轉換隱式地轉換為該型別。一些例子如下:
class Sample<T> where T : Stream { }//有效:Sample<Stream>(一致性轉換) //無效:Sample<string> class Sample<T> where T : IDisposable { }//有效:Sample<Stream>(引用轉換) //無效:Sample<string> class Sample<T> where T : IComparable<T> { }//有效:Sample<int>(裝箱轉換) //無效:Sample<FileInfo> class Sample<T,U> where T : U { }//有效:Sample<Stream,IDisposable>(引用轉換) //無效:Sample<string,IDisposable>