将基类的派生类转换为列表<>

我有两个类:一个基类(Animal)和一个从它派生的类(Cat).Base类包含一个虚拟方法Play,它将List作为input参数。像这样的东西

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

当我编译上面的程序,我得到以下错误

    错误2参数1:无法从“System.Collections.Generic.List”转换为“System.Collections.Generic.List”

有没有办法做到这一点?

你不能这样做的原因是因为列表是可写的。 假设这是合法的,看看出了什么问题:

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

好狗我的猫,那就是坏话。

您想要的function称为“通用协方差”,并且在C#4中为已知安全的接口提供支持。 IEnumerable<T>没有任何方式写入序列,所以它是安全的。

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

这将在C#4中工作,因为List<Cat>可以转换为IEnumerable<Cat> ,它可以转换为IEnumerable<Animal> 。 Play无法使用IEnumerable<Animal>将狗添加到实际上是猫列表的东西上。

你可以做一些事情。 一个例子是将列表的元素投入到Animal

使用你的代码:

 cat.Play(new List<Cat>().Cast<Animal>().ToList()); 

另一个是使Animal通用,所以cat.Play(new List<Cat>()); 会工作。

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

另一种方法是不要使Animal通用,但是对于T : AnimalPlay方法和限制

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

最后,如果你使用C#4,只需要枚举列表而不修改它,请查看Eric Lippert在IEnumerable<Animal>上的答案。

您正在寻找通用收集协方差。 显然,这个function不支持你正在使用的C#版本。

您可以使用Cast<T>()扩展方法解决此问题。 但请注意,这将创build您的原始列表的副本,而不是将原始格式作为其他types传递:

 cat.Play((new List<Cat>()).Cast<Animal>().ToList()); 

使用扩展方法Cast()

所以:

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

这是因为B / C .net 3.5不支持协方差,但4.0呢:)

每个人都已经提到了施放方法。 如果你不能更新到4.0隐藏的演员的方式是

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

这与GetEnumerator的IEnumableIEnumarable<T>玩法是一样的