Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# generics - why is an explicit cast needed to from a concrete type back to T?

Tags:

c#

This has been bothering me for a while. I'm having a little trouble understanding why explicit casts are needed in the following code:

public static class CastStrangeness
{
    public class A
    {
    }

    public class B
        : A
    {
    }

    public static void Foo<T>(T item)
        where T : A
    {
        // Works.
        A fromTypeParameter = item;

        // Does not compile without an explicit cast.
        T fromConcreteType = (T)fromTypeParameter;

        // Does not compile without an explicit cast.
        Foo<T>((T)fromTypeParameter);
    }

    public static void Bar(A item)
    {
        // Compiles.
        Foo<A>(item);
    }
}

It seems to me that T is guaranteed to be an A, so surely the compiler could infer that any instance of A is guaranteed to be assignable to T? Otherwise, I wouldn't be able to pass an A or a B into Foo(). So what am I missing?

PS. I've tried searching for endless permutations of keywords on this, but every result seems to wind up referring to covariance and contravariance WRT generic interfaces :)

like image 226
tintoy Avatar asked Dec 22 '22 07:12

tintoy


2 Answers

Take the case of:

Foo(new B());

Your first assignment is ok:

A fromtypeParameter = item;

Since B : A.

But this assignment is not ok:

T fromConcreteType = fromTypeParameter;

Because you could very well have assigned fromTypeParameter as:

fromTypeParameter = new A();

Which you obviously cannot cast to T (which is B in this instance). T is more specific than A, it could be derived from A. So you can go one way but not the other, without an explicit cast (which may fail).

like image 124
InfinitiesLoop Avatar answered Dec 24 '22 01:12

InfinitiesLoop


It seems to me that T is guaranteed to be an A, so surely the compiler could infer that any instance of A is guaranteed to be assignable to T?

Well, no.

string is an object. But

string s = new object();

is illegal.

like image 40
Ben Voigt Avatar answered Dec 24 '22 01:12

Ben Voigt