Vincent van der Weele
Vincent van der Weele

Reputation: 13187

Why can't I use covariance with two generic type parameters?

Consider the following example:

class Base {}

class Derived : Base {}

class Test1
{
    private List<Derived> m_X;

    public IEnumerable<Base> GetEnumerable()
    {
        return m_X;
    }
}

This compiles just fine, because IEnumerable<T> is covariant in T.

However, if I do exactly the same thing but now with generics:

class Test2<TBase, TDerived> where TDerived : TBase
{
    private List<TDerived> m_X;

    public IEnumerable<TBase> GetEnumerable()
    {
        return m_X;
    }
}

I get the compiler error

Cannot convert expression type 'System.Collection.Generic.List' to return type 'System.Collection.Generic.IEnumerable'

What am I doing wrong here?

Upvotes: 15

Views: 933

Answers (1)

AgentFire
AgentFire

Reputation: 9800

Thing is, in the first case, the Base is known to be a class. In the second case, the type parameter T could be either class or a struct (this is how compiler thinks).

Solve the case by specifying that T is a class, and the error will disappear:

class Test2<TBase, TDerived> where TDerived : class, TBase
{
    private List<TDerived> m_X;

    public IEnumerable<TBase> GetEnumerable()
    {
        return m_X;
    }
}

So, the compiler tries to show us that TDerived could be a struct (since you didn't specify class constraint) and as we already know, covariance and contravariance do not work with structs.

Upvotes: 14

Related Questions