C# Generic Constraints

In this chapter you will learn:

  1. What are Generic Constraints
  2. Type of constraints
  3. Example for Generic Constraints
  4. Note for Generic Constraints
  5. Example for base class constraint or interface constraint
  6. Example for class constraint and struct constraint
  7. Example for parameterless constructor constraint
  8. Example for naked type constraint

Description

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.

Type of constraints

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
//from  ww  w. j  a  v  a2  s  .c o  m

Example

In the following example, GenericClass<T,U> requires T to derive from MyClass and implement MyInterface, and requires U to provide a parameterless constructor:


class     MyClass {}
interface MyInterface {}
//from  w  w w  .j av a 2 s.com
class GenericClass<T> where T : MyClass, MyInterface
                      where U : new()
{}

Note

Constraints can be applied wherever type parameters are defined, in both methods and type definitions.

Example 2

A base class constraint or interface constraint specifies that the type parameter must subclass or implement a particular class or interface. This allows instances of that type to be implicitly cast to that class or interface.

For example, suppose we want to write a generic Max method, which returns the maximum of two values.

We can take advantage of the generic interface defined in the framework called IComparable<T>:


public interface IComparable<T>   // Simplified version of interface
{
 int CompareTo (T other);
}

CompareTo returns a positive number if other is greater than this. Using this 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> which includes most built-in types such as int and string:


int z = Max (5, 10);               // 10
string last = Max ("ant", "zoo");  // zoo

Example 3

The class constraint and struct constraint specify that T must be a reference type or (non-nullable) value type.

A great example of the struct constraint is the System.Nullable<T> struct:


struct Nullable<T> where T : struct {...}

Example 4

The parameterless constructor constraint requires T to have a public parameterless constructor. If this constraint is defined, you can call new() on T:

                                                                                          
static void Initialize<T> (T[] array) where T : new()
{//from   w ww  .j a v  a  2s  .  c o  m
  for (int i = 0; i < array.Length; i++)
    array[i] = new T();
}    

Example 5

The naked type constraint requires one type parameter to derive from another type parameter.

In this example, the method FilteredStack returns another Stack, containing only the subset of elements where the type parameter T is of the type parameter U:


class Stack<T>
{
  Stack<U> FilteredStack<U>() where U : T {...}
}

Next chapter...

What you will learn in the next chapter:

  1. What
  2. Example for Subclassing Generic Types
Home »
  C# Tutorial »
    C# Types »
      C# Generics
C# Generic Types
C# Generic Methods
C# default Generic Value
C# Generic Constraints
C# Subclassing Generic Types
C# Generic Delegate
C# Type Parameters