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 typeIEnumerable<out T>
is declared with variant type parametersT
is covariantan implicit reference conversion exists from
TBase
toIBase
So - is it a bug in the C# 4 compiler?
: class
). It may be assignable, but it is not necessarily a reference-conversion. Without the: class
it is a "constrained" conversion, which is some magic that lets the same IL call methods (including property accessors) on reference-types and value-types in the same way: msdn.microsoft.com/en-us/library/… – Zhao