Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class and Method level generic type constraints interaction

Consider the following class:

public class DerivedClassPool<TBase> where TBase : class
{
    public TBase Get(Type componentType)
    {
        // Not important, but you get the idea
        return Activator.CreateInstance(componentType) as TBase;
    }

    public TDerived SomeMethod<TDerived>() where TDerived : TBase
    {
        return Get(typeof(TBase)) as TDerived;
    }
}

Note that I've restricted the TBase generic class argument to be a class: where TBase : class
I've also restricted the TDerived generic method argument to be TBase or something derived from that: where TDerived : TBase.

I get an error on the as TDerived line:

The type parameter 'TDerived' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

I understand that to prevent the error I need to add the constraint class, so I'd get:

where TDerived : class, TBase

Why do I have to do this when TBase is already constrained to be a class and TDerived is constrained to be a TBase or derived from it?

like image 317
George Duckett Avatar asked Jan 17 '12 16:01

George Duckett


People also ask

How do you specify a constraint for the type to be used in a generic class?

It will give a compile-time error if you try to instantiate a generic type using a type that is not allowed by the specified constraints. You can specify one or more constraints on the generic type using the where clause after the generic type name.

What does the generic constraint of type interface do?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.

Which interface defines methods to control the different generic collections?

NET class library defines several generic interfaces for use with the collection classes in the System. Collections. Generic namespace.

Which of the following generic constraints restricts the generic type parameter to an object of the class?

Value type constraint If we declare the generic class using the following code then we will get a compile-time error if we try to substitute a reference type for the type parameter.


2 Answers

UPDATE: This question was the subject of my blog on September 19th, 2011. Thanks for the great question!


Why do i have to do this when TBase is already constrained to be a class and TDerived is constrained to be a TBase or derived from it?

Because a value type can be derived from a reference type. int is derived from reference types object and System.ValueType and implements a number of interfaces. That doesn't make int a reference type.

It is perfectly legal for you to call SomeMethod<int> on an instance of DerivedClassPool<object> because int is derived from object.

Now, there are cases where your criticism would be warranted. One can construct situations in which two type parameters are related in such a way that both of them logically can only be reference types, but only one of them is classified by the language as "known to be of reference type".

As an exercise to the reader: can you find one? It might be necessary to carefully read section 10.1.5 of the specification for a precise definition of "known to be a reference type".

like image 129
Eric Lippert Avatar answered Sep 18 '22 20:09

Eric Lippert


Because TBase could be an interface and therefore TDerived could be a value type.

like image 24
Andras Zoltan Avatar answered Sep 17 '22 20:09

Andras Zoltan