By default, a type parameter can be substituted with any type whatsoever.
Constraints can be applied to a type parameter to require more specific type arguments.
These are the possible constraints:
where T : base-class // Base-class constraint where T : interface // Interface constraint where T : class // Reference-type constraint where T : struct // Value-type constraint (excludes Nullable types) where T : new() // Parameterless constructor constraint where U : T // Naked type constraint
In the following example, GenericClass<T,U>
requires T
to derive from
Main
and implement Interface1
,
and requires U
to provide a parameterless
constructor:
class Main {} interface Interface1 {} class GenericClass<T,U> where T : Main, Interface1 where U : new() { ... }
Constraints can be applied wherever type parameters are defined, in both methods and type definitions.
A base-class constraint specifies that the type parameter must subclass a particular class.
An interface constraint specifies that the type parameter must implement that interface.
The following code shows how to write a generic Max method, which returns the maximum of two values.
We can use the generic interface defined in the framework called IComparable<T>
:
public interface IComparable<T> // Simplified version of interface { int CompareTo (T other); }
The following code uses IComparable
interface
as a constraint, we can write a Max
method as follows:
static T Max <T> (T a, T b) where T : IComparable<T> {
return a.CompareTo (b) > 0 ? a : b;
}
The Max
method can accept arguments of any type implementing IComparable<T>
:
int z = Max (5, 10); // 10 string last = Max ("A", "B");
A generic class can be subclassed like a nongeneric class.
The subclass can leave the base class's type parameters open, as in the following example:
class Stack<T> {...} class SpecialStack<T> : Stack<T> {...}
Or the subclass can close the generic type parameters with a concrete type:
class IntStack : Stack<int> {...}
A subtype can also introduce fresh type arguments:
class List<T> {...} class KeyedList<T,TKey> : List<T> {...}