CONSTRAINING TYPES

Wherever generic type parameters are used, they can also be constrained through the use of a where clause. Here’s an example using a method:

static void OutputValue<T>(T value) where T : ListItem<string> {

  Console.WriteLine("String list value: {0}", value.Value);

}

The declaration of the constraint is straightforward in this example: the type T has to be compatible with ListItem<string>. It is tempting to say “T needs to be derived from ListItem<string>,” which the colon seems to signify, but that wouldn’t be correct because ListItem<string> itself is a valid type in this example. The generic type constraint T : X means that T may be equal to X, derived from X, or implementing X (if X is an interface). In other words, if you had an instance of type T called t, you would be able to assign a variable like this:

X x = t;

Constraints can mention specific types, like the preceding example, and in these cases the types can’t be sealed. There are several special keywords that can be used instead of or in addition to a type specifier. The keyword class can specify that the type has to be a reference type, while struct denotes that it has to be a value type. In combination with class or with any specific type, the new() keyword (which must include the parentheses) can be used to require a default constructor on the type (that’s a constructor without any parameters).

The final use of a constraint is to define a relationship between two type parameters. For instance, ...

Get Functional Programming in C#: Classic Programming Techniques for Modern Projects now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.