與C++模板不同,C#模板增加了對於泛化類的約束問題,泛化類約束共計4中類型:
基類約束:要求泛化類必須繼承至某個基類。
接口約束:要求泛化類必須實現某個接口。
構造函數約束:要求泛化類必須提供默認的構造函數。
值/引用數據類型約束:要求泛化類只能爲值類型或引用類型。
1. 基類約束,當出現多個約束時,基類約束必須放在最前面,基類約束中的基類不能是sealed class(密封類)和非值類型。
public class Base {
}
public class Derived: Base {
}
public class TBase<T>
where T : Base {
}
2. 接口約束,如下面的程序,如果未約束IComparable接口,方法就需要進行強制轉換爲IComparable接口,再調用CompareTo方法,轉換過程中可能會拋出異常或者出現C++大量無法定位源的錯誤信息。
public class TCompare<T>
where T: System.IComparable<T>
{
public void Method( T t1, T t2)
{
Console.WriteLine("t1:{0},t2:{1},t1 < t2:{2}",t1,t2,t1.CompareTo(t2));
}
}
3. 構造函數約束:只支持默認構造器約束
public class TDerived<T>
where T : new() {
}
4. 值/引用數據類型約束
public struct A {
};
public struct TA<T>
where T : struct {
}
其中Nullable<T>不能嵌套,即Nullable<Nullable<T>>,該項爲編譯器特殊規定,一個可空的”可空類型”是毫無意義的。5. 約束繼承
當出現模板類約束繼承時,需將父類中的約束添加至子類中,而方法約束時,則無需將父類中的方法約束添加至子類中。
public class TBase<T>
where T : Base {
public virtual void Foo<T>(T t )
where T:System.IComparable<T>
{
}
}
public class TDerived<T>
where T : new() {
}
public class TDerived2<T>:TBase<T>
where T : Base,new()
{
public virtual void Foo<T>(T t)
{
}
}
約束還有一些限制性的條件,如不能實現運算符約束、不支持OR選擇約束。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Generic
{
public struct A {
};
public struct TA<T>
where T : struct {
}
public class Base {
}
public class Derived: Base {
Derived(int value) {}
}
public class TBase<T>
where T : Base {
public virtual void Foo<T>(T t )
where T:System.IComparable<T>
{
}
}
public class TDerived<T>
where T : new() {
}
public class TDerived2<T>:TBase<T>
where T : Base,new()
{
public virtual void Foo<T>(T t)
{
}
}
public class TCompare<T>
where T: System.IComparable<T>
{
public void Method( T t1, T t2)
{
Console.WriteLine("t1:{0},t2:{1},t1 < t2:{2}",t1,t2,t1.CompareTo(t2));
}
}
class Program
{
static void Main(string[] args)
{
TCompare<int> t = new TCompare<int>();
t.Method(1, 2);
TBase<Derived> s = new TBase<Derived>();
TA<TA<int>> ta = new TA<TA<int>>();
TDerived<Base> td = new TDerived<Base>();
Console.ReadLine();
}
}
}