C # List < Interface > : 为什么不能做“ List < IFoo > foo = new List < Bar >() ;”

如果您有一个接口 IFoo和一个类 Bar : IFoo,为什么可以执行以下操作:

List<IFoo> foo = new List<IFoo>();
foo.Add(new Bar());

但你不能这样做:

List<IFoo> foo = new List<Bar>();
65286 次浏览

它与 List 的创建有关,您已经指定了 T 为 IFoo,因此您不能将它实例化为一个 Bar,因为它们是不同的类型,即使 Bar 支持 IFoo。

List 是本例中的类型,它不是继承问题 List < IFoo > 与 List < Bar > 确实不同。List 不知道或继承任何 IFoo 或 Bar 的特征。

希望能帮上忙。

List<Bar>不从 List<IFoo>继承

如果您有一个类型为 List<IFoo>的列表,那么您可以调用 list.add(new Baz());,前提是 Baz实现了 IFoo。但是你不能使用 List<Bar>,所以你不能在任何你能使用 List<IFoo>的地方使用 List<Bar>

然而,由于 Bar实现了 IFoo,所以在使用 IFoo的任何地方都可以使用 Bar,因此传递 Bar 以便在它预期和 IFoo时添加工作。

原因是 C # 不支持 C # 3.0或更早版本中的泛型的协变和逆变。这是在 C # 4.0中实现的,因此您可以执行以下操作:

IEnumerable<IFoo> foo = new List<Bar>();

请注意,在 C # 4.0中,您可以将其转换为 IEnumable < IFoo > ,但不能将其转换为 List < IFoo > 。其原因是由于类型安全,如果您能够将 List < Bar > 强制转换为 List < IFoo > ,那么您就能够将其他 IFoo 实现者添加到列表中,从而破坏了类型安全。

想了解更多关于 C # 反变的背景知识,埃里克 · 利伯特提供了一个 不错的博客系列

因为一个 IFoo列表也可以包含一些 Bar,但是一个 IFoo列表和一个 Bar列表是一样的。

注意,我在上面使用了英语而不是 C # 。我想强调的是,这不是一个深层次的问题; 您只是对语法的细节感到困惑。要理解这个答案,你需要看到语法之外的东西,并思考它的实际含义。

IFoo列表可以包含 Bar,因为 Bar也是 IFoo。这里我们讨论的是列表的元素。这个列表仍然是 IFoo的列表。我们没有改变这一点。

现在,您称为 foo的列表仍然是 IFoo的列表(更迂腐地说,foo被声明为 List<IFoo>)。不可能是别的。特别是,它不能被制作成 Bar(List<Bar>)的列表。Bar列表与 IFoo列表是完全不同的对象。

乍一看,似乎这 应该(如在啤酒 应该是免费的)的工作。然而,一个快速的理智检查告诉我们为什么它不能。请记住以下代码 将无法编译。这是为了说明为什么它不允许,即使它 看起来直到一个点。

public interface IFoo { }
public class Bar : IFoo { }
public class Zed : IFoo { }


//.....


List<IFoo> myList = new List<Bar>(); // makes sense so far


myList.Add(new Bar()); // OK, since Bar implements IFoo
myList.Add(new Zed()); // aaah! Now we see why.


//.....

myListList<IFoo>,这意味着它可以采用 IFoo的任何实例。但是,这与它被实例化为 List<Bar>的事实相冲突。因为有一个 List<IFoo>意味着我可以添加一个新的 Zed实例,我们不能允许这样做,因为底层列表实际上是 List<Bar>,它不能容纳一个 Zed

如果需要将列表转换为基类或接口的列表,可以这样做:

using System.Linq;


---


List<Bar> bar = new List<Bar>();
bar.add(new Bar());


List<IFoo> foo = bar.OfType<IFoo>().ToList<IFoo>();

我使用了一些 linq 来简化转换

List<Bar> bar = new List<Bar>();
bar.add(new Bar());


List<IFoo> foo = bar.Select(x => (IFoo)x).ToList();

与其他答案相比,这个答案没有那么冗长,但是很有效