where(泛型类型约束)(C# 参考)where (generic type constraint) (C# Reference)

泛型定义中的 where 子句指定对用作泛型类型、方法、委托或本地函数中类型参数的参数类型的约束。The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. 约束可指定接口、基类或要求泛型类型为引用、值或非托管类型。Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type. 它们声明类型参数必须具备的功能。They declare capabilities that the type argument must possess.

例如,可以声明一个泛型类 MyGenericClass,以使类型参数 T 实现 IComparable<T> 接口:For example, you can declare a generic class, MyGenericClass, such that the type parameter T implements the IComparable<T> interface:

public class AGenericClass<T> where T : IComparable<T> { }


有关查询表达式中的 where 子句的详细信息,请参阅 where 子句For more information on the where clause in a query expression, see where clause.

where 子句还可包括基类约束。The where clause can also include a base class constraint. 基类约束表明用作该泛型类型的类型参数的类型具有指定的类作为基类(或者是该基类),以用作该泛型类型的类型参数。The base class constraint states that a type to be used as a type argument for that generic type has the specified class as a base class (or is that base class) to be used as a type argument for that generic type. 该基类约束一经使用,就必须出现在该类型参数的所有其他约束之前。If the base class constraint is used, it must appear before any other constraints on that type parameter. 某些类型不允许作为基类约束:ObjectArrayValueTypeSome types are disallowed as a base class constraint: Object, Array, and ValueType. 在 C# 7.3 之前,EnumDelegateMulticastDelegate 也不允许作为基类约束。Prior to C# 7.3, Enum, Delegate, and MulticastDelegate were also disallowed as base class constraints. 以下示例显示现可指定为基类的类型:The following example shows the types that can now be specified as a base class:

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 子句可指定类型为 classstructThe where clause can specify that the type is a class or a struct. struct 约束不再需要指定 System.ValueType 的基类约束。The struct constraint removes the need to specify a base class constraint of System.ValueType. System.ValueType 类型可能不用作基类约束。The System.ValueType type may not be used as a base class constraint. 以下示例显示 classstruct 约束:The following example shows both the class and struct constraints:

class MyClass<T, U>
    where T : class
    where U : struct
{ }

where 子句可能包含 notnull 约束。The where clause may include the notnull constraint. notnull 约束将类型参数限制为不可为 null 的类型。The notnull constraint limits the type parameter to non-nullable types. 该类型可以是值类型,也可以是不可为 null 的引用类型。That type may be a value type or a non-nullable reference type. 对于在 nullable enable 上下文中编译的代码,从 C# 8.0 开始可以使用 notnull 约束。The notnull constraint is available starting in C# 8.0 for code compiled in a nullable enable context. 与其他约束不同,如果类型参数违反 notnull 约束,编译器会生成警告而不是错误。Unlike other constraints, if a type argument violates the notnull constraint, the compiler generates a warning instead of an error. 警告仅在 nullable enable 上下文中生成。Warnings are only generated in a nullable enable context.


包含 notnull 约束的泛型声明可以在可为 null 的不明显上下文中使用,但编译器不会强制执行约束。Generic declarations that include the notnull constraint can be used in a nullable oblivious context, but compiler does not enforce the constraint.

#nullable enable
    class NotNullContainer<T>
        where T : notnull
#nullable restore

where 子句还可包括 unmanaged 约束。The where clause may also include an unmanaged constraint. unmanaged 约束将类型参数限制为名为“非托管类型”的类型。The unmanaged constraint limits the type parameter to types known as unmanaged types. unmanaged 约束使得在 C# 中编写低级别的互操作代码变得更容易。The unmanaged constraint makes it easier to write low-level interop code in C#. 此约束支持跨所有非托管类型的可重用例程。This constraint enables reusable routines across all unmanaged types. unmanaged 约束不能与 classstruct 约束结合使用。The unmanaged constraint can't be combined with the class or struct constraint. unmanaged 约束强制该类型必须为 structThe unmanaged constraint enforces that the type must be a struct:

class UnManagedWrapper<T>
    where T : unmanaged
{ }

where 子句也可能包括构造函数约束 new()The where clause may also include a constructor constraint, new(). 该约束使得能够使用 new 运算符创建类型参数的实例。That constraint makes it possible to create an instance of a type parameter using the new operator. new() 约束可以让编译器知道:提供的任何类型参数都必须具有可访问的无参数构造函数。The new() Constraint lets the compiler know that any type argument supplied must have an accessible parameterless constructor. 例如:For example:

public class MyGenericClass<T> where T : IComparable<T>, new()
    // The following line is not possible without new() constraint:
    T item = new T();

new() 约束出现在 where 子句的最后。The new() constraint appears last in the where clause. new() 约束不能与 structunmanaged 约束结合使用。The new() constraint can't be combined with the struct or unmanaged constraints. 所有满足这些约束的类型必须具有可访问的无参数构造函数,这使得 new() 约束冗余。All types satisfying those constraints must have an accessible parameterless constructor, making the new() constraint redundant.

对于多个类型参数,每个类型参数都使用一个 where 子句,例如:With multiple type parameters, use one where clause for each type parameter, for example:

public interface IMyInterface { }

namespace CodeExample
    class Dictionary<TKey, TVal>
        where TKey : IComparable<TKey>
        where TVal : IMyInterface
        public void Add(TKey key, TVal val) { }

还可将约束附加到泛型方法的类型参数,如以下示例所示:You can also attach constraints to type parameters of generic methods, as shown in the following example:

public void MyMethod<T>(T t) where T : IMyInterface { }

请注意,对于委托和方法两者来说,描述类型参数约束的语法是一样的:Notice that the syntax to describe type parameter constraints on delegates is the same as that of methods:

delegate T MyDelegate<T>() where T : new();

有关泛型委托的信息,请参阅泛型委托For information on generic delegates, see Generic Delegates.

有关约束的语法和用法的详细信息,请参阅类型参数的约束For details on the syntax and use of constraints, see Constraints on Type Parameters.

C# 语言规范C# language specification

有关详细信息,请参阅 C# 语言规范For more information, see the C# Language Specification. 该语言规范是 C# 语法和用法的权威资料。The language specification is the definitive source for C# syntax and usage.

请参阅See also