泛型定义中的 where
子句指定对用作泛型类型、方法、委托或本地函数中类型参数的参数类型的约束。 约束可指定接口、基类或要求泛型类型为引用、值或非托管类型。 它们声明类型参数必须具备的功能。
例如,可以声明一个泛型类 MyGenericClass
,以使类型参数 T
实现 IComparable<T> 接口:
public class AGenericClass<T> where T : IComparable<T> { }
where
子句还可包括基类约束。 基类约束表明用作该泛型类型的类型参数的类型具有指定的类作为基类(或者是该基类),以用作该泛型类型的类型参数。 该基类约束一经使用,就必须出现在该类型参数的所有其他约束之前。 某些类型不允许作为基类约束:Object、Array 和 ValueType。 在 C# 7.3 之前,Enum、Delegate 和 MulticastDelegate 也不允许作为基类约束。 以下示例显示现可指定为基类的类型:
public class UsingEnum<T> where T : System.Enum { }
public class UsingDelegate<T> where T : System.Delegate { }
public class Multicaster<T> where T : System.MulticastDelegate { }
where
子句可指定类型为 class
或 struct(结构体)
。 struct
约束不再需要指定 System.ValueType
的基类约束。 System.ValueType
类型可能不用作基类约束。以下示例显示 class
和 struct
约束:
class MyClass<T, U>
where T : class
where U : struct
{ }
where
子句还可包括 unmanaged
约束。 unmanaged
约束将类型参数限制为名为“非托管类型”的类型。 unmanaged
约束使得在 C# 中编写低级别的互操作代码变得更容易。 此约束支持跨所有非托管类型的可重用例程。 unmanaged
约束不能与 class
或 struct
约束结合使用。 unmanaged
约束强制该类型必须为 struct
:
class UnManagedWrapper<T>
where T : unmanaged
{ }
where
子句也可能包括构造函数约束 new()
。 该约束使得能够使用 new
运算符创建类型参数的实例。 new() 约束可以让编译器知道:提供的任何类型参数都必须具有可访问的无参数(或默认)构造函数。 例如:
public class MyGenericClass<T> where T : IComparable<T>, new()
{
// The following line is not possible without new() constraint:
T item = new T();
}
new()
约束出现在 where
子句的最后。 new()
约束不能与 struct
或 unmanaged
约束结合使用。 所有满足这些约束的类型必须具有可访问的无参数构造函数,这使得 new()
约束冗余。
对于多个类型参数,每个类型参数都使用一个 where
子句,例如:
public interface IMyInterface { }
namespace CodeExample
{
class Dictionary<TKey, TVal>
where TKey : IComparable<TKey>
where TVal : IMyInterface
{
public void Add(TKey key, TVal val) { }
}
}
还可将约束附加到泛型方法的类型参数,如以下示例所示:
public void MyMethod<T>(T t) where T : IMyInterface { }
请注意,对于委托和方法两者来说,描述类型参数约束的语法是一样的:
delegate T MyDelegate<T>() where T : new();
有关泛型委托的信息,请参阅泛型委托。
有关约束的语法和用法的详细信息,请参阅类型参数的约束。