In the following piece of code I expected to be able to implicitly cast from elements
to baseElements
because TBase
is implicitly convertible to IBase
.
public interface IBase { } public interface IDerived : IBase { } public class VarianceBug { public void Foo<TBase>() where TBase : IBase { IEnumerable<TBase> elements = null; IEnumerable<IDerived> derivedElements = null; IEnumerable<IBase> baseElements; // works fine baseElements = derivedElements; // error CS0266: Cannot implicitly convert type // 'System.Collections.Generic.IEnumerable<TBase>' to // 'System.Collections.Generic.IEnumerable<IBase>'. // An explicit conversion exists (are you missing a cast?) baseElements = elements; } }
However, I get the error that is mentioned in the comment.
Quoting from the spec:
A type
T<A1, …, An>
is variance-convertible to a typeT<B1, …, Bn>
ifT
is either an interface or a delegate type declared with the variant type parametersT<X1, …, Xn>
, and for each variant type parameterXi
one of the following holds:
Xi
is covariant and an implicit reference or identity conversion exists fromAi
toBi
Xi
is contravariant and an implicit reference or identity conversion exists fromBi
toAi
Xi
is invariant and an identity conversion exists fromAi
toBi
Checking my code, it appears to be consistent with the spec:
IEnumerable<out T>
is an interface type
IEnumerable<out T>
is declared with variant type parameters
T
is covariant
an implicit reference conversion exists from TBase
to IBase
So - is it a bug in the C# 4 compiler?
Variance only works for reference-types (or there is an identity conversion). It is not known that TBase
is reference type, unless you add : class
:
public void Foo<TBase>() where TBase : class, IBase
since I could write a:
public struct Evil : IBase {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With