Casting List de la clase Derivada a List de la clase base

Tengo dos clases: una clase base (Animal) y una clase derivada de ella (Cat). La clase Base contiene un método virtual Play que toma la lista como parámetro de entrada. Algo como esto

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication9 { class Animal { public virtual void Play(List animal) { } } class Cat : Animal { public override void Play(List animal) { } } class Program { static void Main(string[] args) { Cat cat = new Cat(); cat.Play(new List()); } } } 

Cuando compilo el progtwig anterior, aparece el siguiente error

     Error 2 Argumento 1: no se puede convertir de 'System.Collections.Generic.List' a 'System.Collections.Generic.List'

¿Hay alguna forma de lograr esto?

La razón por la que no puede hacer esto es porque una lista es escribible. Supongamos que fuera legal, y vea qué va mal:

 List cats = new List(); List animals = cats; // Trouble brewing... animals.Add(new Dog()); // hey, we just added a dog to a list of cats... cats[0].Speak(); // Woof! 

Bueno, perro mis gatos, eso es maldad.

La característica que desea se denomina “covarianza genérica” ​​y es compatible con C # 4 para las interfaces que se sabe que son seguras. IEnumerable no tiene forma de escribir en la secuencia, por lo que es seguro.

 class Animal { public virtual void Play(IEnumerable animals) { } } class Cat : Animal { public override void Play(IEnumerable animals) { } } class Program { static void Main() { Cat cat = new Cat(); cat.Play(new List()); } } 

Eso funcionará en C # 4 porque List es convertible a IEnumerable , que es convertible a IEnumerable . No hay forma de que Play pueda usar IEnumerable para agregar un perro a algo que en realidad es una lista de gatos.

Podrías hacer algunas cosas. Un ejemplo es lanzar los elementos de la lista a Animal

Usando tu código:

 cat.Play(new List().Cast().ToList()); 

Otra es hacer Animal genérico, así que cat.Play(new List()); trabajaría.

 class Animal { public virtual void Play(List animals) { } } class Cat : Animal { public override void Play(List cats) { } } class Program { static void Main(string[] args) { Cat cat = new Cat(); cat.Play(new List()); } } 

Otro método es no hacer Animal genérico, sino el método Play y restringir eso a T : Animal

 class Animal { public virtual void Play(List animals) where T : Animal { } } class Cat : Animal { public override void Play(List animals) { } } 

Finalmente, si está en C # 4 y solo necesita enumerar la lista y no modificarla, consulte la respuesta de Eric Lippert en IEnumerable .

Está buscando covarianza de colección genérica. Obviamente, sin embargo, esa característica no es compatible con la versión de C # que estás usando.

Puede solucionarlo utilizando el método de extensión Cast() . Tenga en cuenta, sin embargo, que esto creará una copia de su lista original en lugar de pasar el original como un tipo diferente:

 cat.Play((new List()).Cast().ToList()); 

usa el método de extensión Cast ()

asi que:

 class Program { static void Main(string[] args) { Cat cat = new Cat(); cat.Play(new List().Cast()); } } 

La razón para esto es b / c .net 3.5 no admite covarianza, pero 4.0 sí 🙂

Todo el mundo menciona el método de lanzamiento ya. Si no puede actualizar a 4.0, una forma de ocultarlo es

 class Cat : Animal { public override void Play(List animal) { Play((List)animal); } public virtual void Play(List animal) { } } 

Este es el mismo truco que IEnumable e IEnumarable juegan para GetEnumerator