對於沒有類型約束的泛型,其類型參數可以指定為任意類型。
例如List<T>,其類型參數T是值類型(List<int>)或引用類型(List<object>)。
有時候,我們希望泛型的類型參數只能是值類型或引用類型,這時就該論到類型約束上場了。
約束要放到泛型方法或泛型類型聲明的末尾,並由關鍵字where來引入。
在C#中,有4中類型約束可供使用。
1、引用類型約束
這種約束用於確保使用的類型實參是應用類型。類型實參可以是任何類。接口。數組。委托,或者已知是引用類型的另外一個類型參數。例如以下聲明:
class Sample<T> where T : 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>