Search code examples
c#genericscovariance

Covariance problems in C#


Here's the setup:

interface IFruit { }
interface IApple : IFruit { }
interface IBag<out T> { }

// This works
IBag<IFruit> ConvertBag(IBag<IApple> fruits) => fruits; 

// Error: Cannot implicitly convert IBag<F> to IBag<IFruit>
IBag<IFruit> ConvertBag<F>(IBag<F> fruits) where F : IFruit => fruits; 

As expected, I can convert an IBag<IApple> to an IBag<IFruit>. But, why can't I convert an IBag<F> to an IBag<IFruit> if I know that F is an IFruit?


Solution

  • But, why can't I convert an IBag<F> to an IBag<IFruit> if I know that F is an IFruit?

    Because F might be a value type, and variance effectively "doesn't work" with value types. (For example, you can't assign an IEnumerable<int> to a variable of type IEnumerable<object>.)

    If you constrain F to be a reference type, it works:

    IBag<IFruit> ConvertBag<F>(IBag<F> fruits) where F : class, IFruit => fruits;
    

    The details are in section 18.2.3.3 of the C# standard: "Variance conversion". The important point is that there's only a reference conversion from F to IFruit when F is constrained to be a reference type.