positiva - ¿Es esto un error de covarianza en C#4?
varianza y covarianza definicion (2)
En el siguiente fragmento de código, esperaba poder convertir implícitamente elements
en elements
baseElements
porque TBase
es implícitamente convertible a 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;
}
}
Sin embargo, obtengo el error que se menciona en el comentario.
Citando de la especificación:
Un tipo
T<A1, …, An>
es convertible en varianza a un tipoT<B1, …, Bn>
siT
es una interfaz o un tipo de delegado declarado con los parámetros de tipo de varianteT<X1, …, Xn>
, y para cada parámetro de tipo de varianteXi
se cumple una de las siguientes condiciones:
Xi
es covariante y existe una referencia implícita o conversión de identidad deAi
aBi
Xi
es contravariante y existe una referencia implícita o conversión de identidad deBi
aAi
Xi
es invariante y existe una conversión de identidad deAi
aBi
Comprobando mi código, parece ser consistente con la especificación:
IEnumerable<out T>
es un tipo de interfazIEnumerable<out T>
se declara con parámetros de tipo de varianteT
es covarianteexiste una conversión de referencia implícita de
TBase
aIBase
Entonces, ¿es un error en el compilador C # 4?
La varianza solo funciona para tipos de referencia (o hay una conversión de identidad ). No se sabe que TBase
es un tipo de referencia, a menos que agregue : class
:
public void Foo<TBase>() where TBase : class, IBase
ya que podría escribir un:
public struct Evil : IBase {}
Marc tiene razón, estaba a punto de pegar la misma respuesta.
Vea las Preguntas Frecuentes de Covarianza y Contravarianza:
http://blogs.msdn.com/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
De las preguntas frecuentes:
"La varianza solo se admite si un parámetro de tipo es un tipo de referencia".
La varianza no es compatible con los tipos de valores
Lo siguiente no compila tampoco:
// int is a value type, so the code doesn''t compile.
IEnumerable<Object> objects = new List<int>(); // Compiler error here.