Marco Scabbiolo Marco Scabbiolo - 1 year ago 59
C# Question

Why is it needed to cast a generic type when a where constraint should be enough

Let's start with the following taxonomy

public abstract class Automobile { }

public class Automobile<T> : Automobile where T : Automobile { }

public class Car : Automobile<Car> { }
public class Truck : Automobile<Truck> { }

public class SmartAutomobile<T> : Automobile<T>
public T MyAutomobile { get; set; }

public SmartAutomobile(SmartTechnology smart)
// Cannot implicitly convert Automobile to T
this.MyAutomobile = AutomobileFromSmart(typeof(T), smart);

public static Automobile AutomobileFromSmart(Type type, SmartTechnology smart)
if (type == typeof(Car))
return new Car
// ...
throw new NotImplementedException("Car type " + type.FullName + " not recognized");

public class SmartTechnology { }

As you can see from the comment, the interpreter says it cannot convert an
's constructor. How can this be? the interpreter should know that
, because of the constraint in
, is an

If I try to explicitly cast it

this.MyAutomobile = AutomobileFromSmart(typeof(T), smart) as T;

I get the interpreter error

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

Now if I also define the
constraint in

public class SmartAutomobile<T> : Automobile<T> where T : Automobile

The interpreter doesn't show any error

But if I remove the explicit cast:

this.MyAutomobile = AutomobileFromSmart(typeof(T), smart);

The Cannot implicitly convert Automobile to T error shows up again.

How can it be that the interpreter doesn't realize the
constraint forces
to be an

Answer Source

How can it be that the interpreter doesn't realize the where constraint forces T to be an Automobile?

No, it forces T to be derived from Automobile. And since down-casting is not always safe, you can't implicitly cast from Automobile to T. If T was Car, but AutomobileFromSmart returned a Truck, then the cast would fail at runtime. You can explicitly cast (or use as) which tells the compiler "I know what I'm doing, and this cast will be safe at run-time").