类型参数的约束
若要检查表中的一个元素,以确定它是否合法或是否可以与其他元素相比较,那么编译器必须保证:客户代码中可能出现的所有类型参数,都要支持所需调用的操作或方法。这种保证是通过在泛型类的定义中,应用一个或多个约束而得到的。一个约束类型是一种基类约束,它通知编译器,只有这个类型的对象或从这个类型派生的对象,可被用作类型参数。一旦编译器得到这样的保证,它就允许在泛型类中调用这个类型的方法。上下文关键字where用以实现约束。下面的示例代码说明了应用基类约束,为MyList<T>类增加功能
public class Employee { public class Employee { private string name; private int id; public Employee(string s, int i) { name = s; id = i; } public string Name { get { return name; } set { name = value; } } public int ID { get { return id; } set { id = value; } } } } class MyList<T> where T: Employee { //Rest of class as before. public T FindFirstOccurrence(string s) { T t = null; Reset(); while (HasItems()) { if (current != null) { //The constraint enables this: if (current.Data.Name == s) { t = current.Data; break; } else { current = current.Next; } } //end if } // end while return t; } }
约束使得泛型类能够使用Employee.Name属性,因为所有为类型T的元素,都是一个Employee对象或是一个继承自Employee的对象。
同一个类型参数可应用多个约束。约束自身也可以是泛型类,如下:
class MyList<T> where T: Employee, IEmployee, IComparable<T>, new() {…}
下表列出了五类约束:
约束 |
描述 |
where T: struct |
类型参数必须为值类型。 |
where T : class |
类型参数必须为引用类型。 |
where T : new() |
类型参数必须有一个公有、无参的构造函数。当于其它约束联合使用时,new()约束必须放在最后。 |
where T : <base class name> |
类型参数必须是指定的基类型或是派生自指定的基类型。 |
where T : <interface name> |
类型参数必须是指定的接口或是指定接口的实现。可以指定多个接口约束。接口约束也可以是泛型的。 |
类型参数的约束,增加了可调用的操作和方法的数量。这些操作和方法受约束类型及其派生层次中的类型的支持。因此,设计泛型类或方法时,如果对泛型成员执行任何赋值以外的操作,或者是调用System.Object中所没有的方法,就需要在类型参数上使用约束。
无限制类型参数的一般用法
没有约束的类型参数,如公有类MyClass<T>{...}中的T, 被称为无限制类型参数(unbounded type parameters)。无限制类型参数有以下规则:
1. 不能使用运算符 != 和 == ,因为无法保证具体的类型参数能够支持这些运算符。
2. 它们可以与System.Object相互转换,也可显式地转换成任何接口类型。
3. 可以与null比较。如果一个无限制类型参数与null比较,当此类型参数为值类型时,比较的结果总为false。
无类型约束
当约束是一个泛型类型参数时,它就叫无类型约束(Naked type constraints)。当一个有类型参数成员方法,要把它的参数约束为其所在类的类型参数时,无类型约束很有用。如下例所示:
class List<T> { //... void Add<U>(List<U> items) where U:T {…} }
在上面的示例中, Add方法的上下文中的T,就是一个无类型约束;而List类的上下文中的T,则是一个无限制类型参数。
无类型约束也可以用在泛型类的定义中。注意,无类型约束一定也要和其它类型参数一起在尖括号中声明:
//naked type constraint public class MyClass<T,U,V> where T : V
因为编译器只认为无类型约束是从System.Object继承而来,所以带有无类型约束的泛型类的用途十分有限。当你希望强制两个类型参数具有继承关系时,可对泛型类使用无类型约束。