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
?
But, why can't I convert an
IBag<F>
to anIBag<IFruit>
if I know thatF
is anIFruit
?
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.