Convertir Lista<DerivedClass> a Lista<BaseClass>
Si bien podemos heredar de la clase/interfaz base, ¿por qué no podemos declarar List<>
usando la misma clase/interfaz?
interface A
{ }
class B : A
{ }
class C : B
{ }
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
List<A> listOfA = new List<C>(); // compiler Error
}
}
¿Hay alguna manera de evitarlo?
La forma de hacer que esto funcione es iterar sobre la lista y convertir los elementos. Esto se puede hacer usando ConvertAll:
List<A> listOfA = new List<C>().ConvertAll(x => (A)x);
También puedes usar Linq:
List<A> listOfA = new List<C>().Cast<A>().ToList();
En primer lugar, deje de usar nombres de clases imposibles de entender como A, B, C. Utilice Animal, Mamífero, Jirafa o Comida, Fruta, Naranja o algo donde las relaciones sean claras.
Tu pregunta entonces es "¿por qué no puedo asignar una lista de jirafas a una variable de tipo lista de animales, ya que puedo asignar una jirafa a una variable de tipo animal?"
La respuesta es: supongamos que podrías. ¿Qué podría salir mal entonces?
Bueno, puedes agregar un tigre a una lista de animales. Supongamos que le permitimos poner una lista de jirafas en una variable que contiene una lista de animales. Luego intentas agregar un tigre a esa lista. ¿Lo que sucede? ¿Quieres que la lista de jirafas contenga un tigre? ¿Quieres un choque? ¿O desea que el compilador lo proteja del bloqueo al hacer que la asignación sea ilegal en primer lugar?
Elegimos este último.
Este tipo de conversión se denomina conversión "covariante". En C# 4 le permitiremos realizar conversiones covariantes en interfaces y delegados cuando se sepa que la conversión siempre es segura . Consulte los artículos de mi blog sobre covarianza y contravarianza para obtener más detalles. (Habrá uno nuevo sobre este tema el lunes y el jueves de esta semana).