与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();
}
}
}