Search code examples
c#genericscovariance

Generic constraint ignores co-variance


Let's say we have an interface like

public interface IEnumerable<out T>
{ /*...*/ }

that is co-variant in T.

Then we have another interface and a class implementing it:

public interface ISomeInterface {}
public class SomeClass : ISomeInterface
{}

Now the co-variance allows us to do the following

IEnumerable<ISomeInterface> e = Enumerable.Empty<SomeClass>();

So a IEnumerable<SomeClass> is assignable to a variable (or method parameter) of type IEnumerable<ISomeInterface>.

But if we try this in a generic method:

public void GenericMethod<T>(IEnumerable<T> p) where T : ISomeInterface
{
    IEnumerable<ISomeInterface> e = p;
    // or
    TestMethod(p);
}
public void TestMethod(IEnumerable<ISomeInterface> x) {}

we get the compiler error CS0266 telling us that an IEnumerable<T> cannot be converted to an IEnumerable<ISomeInterface>.

The constraint clearly states the T is derived from ISomeInterface, and since IEnumerable<T> is co-variant in T, this assignment should work (as shown above).

Is there any technical reason why this cannot work in a generic method? Or anything I missed that makes it too expensive for the compiler to figure it out?


Solution

  • Change your GenericMethod and add generic constraint class:

    public void GenericMethod<T>(IEnumerable<T> p) where T : class, ISomeInterface
    {
        IEnumerable<ISomeInterface> e = p;
        // or
        TestMethod(p);
    }
    

    Covariance does not support structs, so we need to tell that we want to use classes only.