无法从List <bar>转换为List <foo>

时间:2017-07-27 11:31:36

标签: c# .net generics inheritance

我有这样的设置:

abstract class Foo {}
class Bar : Foo {}

以及此形式的其他方法:

void AddEntries(List<Foo>) {}

我试图使用Bar

类型的对象列表来调用此方法
List<Bar> barList = new List<Bar>()
AddEntries(barList);

但这给了我错误:

  

无法从List&lt; Bar&gt;转换列出&lt; Foo&gt;

还有这个问题吗?我需要使用抽象类来保持方法定义。

3 个答案:

答案 0 :(得分:65)

您可以将AddEntries通用并将其更改为此

void AddEntries<T>(List<T> test) where T : Foo
{
    //your logic 
}

请查看Constraints on Type Parameters以获取更多信息。

答案 1 :(得分:60)

请读取Covariance and Contravariance in Generics from docs.microsoft.com,特别是&#34;带有协变类型参数的通用接口&#34; 将涵盖您正在工作的方案用。

简而言之,如果您(可以)将AddEntries方法的签名更改为:

static void AddEntries(IEnumerable<Foo> entries)

(请注意使用IEnumerable<Foo>代替List<Foo>),您将能够做您想做的事情。

此处的具体差异在于IEnumerable<T>List<T>的声明方式不同:

public interface IEnumerable<out T> : IEnumerable
public class List<T> : IList<T>, ... ...

重要的区别在于out声明中的IEnumerable<T>,表示它是协变这意味着(采用了定义)来自docs.microsoft.com):

  

协方差:允许您使用比最初指定的派生类型更多的派生类型。

答案 2 :(得分:43)

由于一个简单的原因,这是不允许的。假设以下编译:

AddEntries(new List<Bar>());

void AddEntries(List<Foo> list)
{
   // list is a `List<Bar>` at run-time
   list.Add(new SomethingElseDerivingFromFoo()); // what ?!
}

如果您的代码会编译,那么您将SomethingElseDerivingFromFoo添加到实际List<Bar>(运行时类型)的位置有一个不安全的添加(这会使整个通用列表毫无意义)。

要解决您的问题,您可以使用泛型:

void AddEntries<T>(List<T> list) where T:Foo
{

}