En el siguiente fragmento de código esperaba poder convertir implícitamente de elements
a baseElements
porque TBase
es implícitamente convertible a IBase
.¿Es esto un error de covarianza en C# 4?
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, me sale el error que se menciona en el comentario.
Citando de la especificación:
Un tipo
T<A1, …, An>
es de varianza-convertible a un tipoT<B1, …, Bn>
siT
es o bien una interfaz o un tipo de delegado declarado con los parámetros de tipo varianteT<X1, …, Xn>
, y para cada parámetro de tipo de varianteXi
una de las siguientes bodegas:
Xi
es covariante y existe una referencia implícita o conversión identidad deAi
aBi
Xi
es contravariant y existe una referencia implícita o conversión identidadBi
-Ai
Xi
es invariante y existe una conversión de identidad a partir deAi
aBi
Comprobación 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 varianteT
es covariante existeuna conversión de referencia implícita
TBase
-IBase
Entonces, ¿es un error en el compilador C# 4?
Qué pasa cuando se desechan de manera explícita? El compilador dice que hay uno. Ya que estás en una postura negativa, ¿tiene sentido ...? – flq
Solo para hacerlo explícito: es su última viñeta "existe una conversión de referencia implícita de TBase a IBase" que no es cierta (a menos que agregue ': clase'). Puede ser asignable, pero * no * necesariamente es una conversión de referencia. Sin ': class', se trata de una conversión" restringida ", que es algo mágico que permite que los mismos métodos de invocación de IL (incluidos los accesores de propiedad) en tipos de referencia y tipos de valor de la misma manera: http://msdn.microsoft .com/en-us/library/system.reflection.emit.opcodes.constrained.aspx –
Charles: está equivocado: la primera asignación funciona (Works on My Machine (TM)). –