One of the more interesting aspects of the base class constraint is that it allows you to establish a relationship between two type parameters. For example, consider the following generic class declaration:
class Gen<T, V> where V : T {
In this declaration, the where clause tells the compiler that V must inherit T. If this relationship is not present when an object of type Gen is declared, then a compile-time error will result. A constraint that uses a type parameter, such as that just shown, is called a naked type constraint. The following example illustrates this constraint:
// Create relationship between two type parameters. using System; class A { //... } class B : A { // ... } // Here, V must inherit T. class Gen<T, V> where V : T { // ... } class NakedConstraintDemo { public static void Main() { // This declaration is OK because B inherits A. Gen<A, B> x = new Gen<A, B>(); // This declaration is in error because // A does not inherit B. // Gen<B, A> y = new Gen<B, A>(); } }
First, notice that class B inherits class A. Next, examine the two Gen declarations in Main( ). As the comments explain, the first declaration:
Gen<A, B> x = new Gen<A, B>();
is legal because B inherits A. However, the second declaration:
// Gen<B, A> y = new Gen<B, A>();
is illegal because A does not inherit B.
Using Multiple Constraints
There can be more than one constraint associated with a parameter. When this is the case, use a comma-separated list of constraints. In this list, the first constraint must be class or struct (if present), or the base class (if one is specified). It is illegal to specify both a class or struct constraint and a base class constraint. Next, must come any interface constraints. The new( ) constraint must be last. For example, this is a valid declaration:
class Gen<T> where T : MyClass, IMyInterface, new() { // ...
In this case, T must be replaced by a type argument that inherits MyClass, implements IMyInterface, and has a parameterless constructor.
When using two or more type parameters, you can specify a constraint for each parameter by using a separate where clause. For example:
// Use multiple where clauses. using System; // Gen has two type arguments and both have // a where clause. class Gen<T, V> where T : class where V : struct { T ob1; V ob2; public Gen(T t, V v) { ob1 = t; ob2 = v; } } class MultipleConstraintDemo { public static void Main() { // This is OK because string is a class and // int is a value type. Gen<string, int> obj = new Gen<string, int>("test", 11); // The next line is wrong because bool is not // a reference type. // Gen<bool, int> obj = new Gen<bool, int>(true, 11); } }
In this example, Gen takes two type arguments, and both have a where clause. Pay special attention to its declaration:
class Gen<T, V> where T : class where V : struct {
Notice that the only thing that separates the first where clause from the second is whitespace. No other punctuation is required or valid.
No comments:
Post a Comment