English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
C# allows you to use constraints to limit the types that client code can specify when instantiating generic types. If you try to instantiate a generic type with a type that is not allowed by the specified constraints, a compile-time error will occur.
You can use the where clause after the generic type name to specify one or more constraints on the generic type.
GenericTypeName<T> where T : contraint1, constraint2
The following example demonstrates a generic class with constraints on reference types when instantiating a generic class.
class DataStore<T> where T : class { public T Data { get; set; } {}
Above, we applied class constraints, which means that only reference types can be passed as arguments when creating DataStore class objects. Therefore, you can pass reference types such as classes, interfaces, delegates, or array types. Passing value types will result in a compile-time error, so we cannot pass primitive data types or struct types.
DataStore<string> store = new DataStore<string>(); // Valid DataStore<MyClass> store = new DataStore<MyClass>(); // Valid DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // Valid DataStore<IEnumerable> store = new DataStore<IMyInterface>(); // Valid DataStore<ArrayList> store = new DataStore<ArrayList>(); // Valid //DataStore<int> store = new DataStore<int>(); // Compile-time Error
The following table lists the types of generic constraints.
Constraints | Description |
---|---|
class | The type parameter must be any class, interface, delegate, or array type. |
class? | The type parameter must be a nullable or non-nullable class, interface, delegate, or array type. |
struct | The type parameter must be a non-empty value type, such as the primitive data types int, char, bool, float, etc. |
new() | The type parameter must be a reference type with a public no-argument constructor. It cannot be combined with struct constraint and unmanaged constraint. |
notnull | from C# 8.0 and later, type parameters can be non-nullable reference types or value types. Otherwise, the compiler will generate a warning instead of an error. |
unmanaged | The type parameter must be a non-nullable unmanaged type. |
base class name | The type parameter must be or derive from the specified base class. It is not allowed to use Object, Array, or ValueType as base class constraints. In C# 7.3Prior to version 8.0, Enum, Delegate, MulticastDelegate were not allowed as base class constraints. |
<base class name>? | The type parameter must be or derive from the specified nullable or non-nullable base class |
<interface name> | The type parameter must be or implement the specified interface. |
<interface name>? | The type parameter must be or implement the specified interface. It can be a nullable reference type, a non-nullable reference type, or a value type |
where T: U | The type parameter provided for T must be or derive from the parameter provided for U. |
The following example demonstrates how to restrict the type parameter to a value type struct constraint that cannot be null.
class DataStore<T> where T : struct { public T Data { get; set; } {} DataStore<int> store = new DataStore<int>(); // Valid DataStore<char> store = new DataStore<char>(); // Valid DataStore<MyStruct> store = new DataStore<MyStruct>(); // Valid //DataStore<string> store = new DataStore<string>(); // Compile-time Error //DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // Compile-time Error //DataStore<ArrayList> store = new DataStore<ArrayList>(); // Compile-time Error
The following example demonstrates how to restrict the type parameter to the base class of a derived class from a specified class, abstract class, or interface.
class DataStore<T> where T : IEnumerable { public T Data { get; set; } {} DataStore<ArrayList> store = new DataStore<ArrayList>(); // Valid DataStore<List> store = new DataStore<List>(); // Valid //DataStore<string> store = new DataStore<string>(); // Compile-time Error //DataStore<int> store = new DataStore<int>(); // Compile-time Error //DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // Compile-time Error //DataStore<MyClass> store = new DataStore<MyClass>(); // Compile-time Error