如果您有一个接口IFoo
和一个类Bar : IFoo
,为什么可以执行以下操作:
List<IFoo> foo = new List<IFoo>();
foo.Add(new Bar());
但是你不能这样做:
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>();
乍一看,这似乎应该(就像啤酒应该是免费的)可以工作。然而,快速的实用性检查向我们展示了它为什么不能工作。请记住以下代码无法编译。它的目的是显示为什么即使它看起来没什么问题,但仍然不被允许。
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.
//.....
myList
是一个 List<IFoo>
,这意味着它可以接受任何 IFoo
的实例。但这与它实例化为 List<Bar>
的事实产生了冲突。由于拥有一个 List<IFoo>
意味着我可以添加一个新的 Zed
实例,但我们不能允许这样做,因为底层列表实际上是 List<Bar>
,无法容纳 Zed
。
List<IFoo> myList = new List<Bar>();
。 - AhammadaliPK原因是C# 3.0或之前版本不支持泛型的协变和逆变。但这在C# 4.0中得到实现,因此您将能够执行以下操作:
IEnumerable<IFoo> foo = new List<Bar>();
注意,在C# 4.0中,你可以将其转换为IEnumerable<IFoo>,但你不能将其转换为List<IFoo>。原因是由于类型安全性,如果你能够将List<Bar>转换为List<IFoo>,那么你就可以向列表中添加其他IFoo实现者,从而破坏类型安全性。using System.Linq;
---
List<Bar> bar = new List<Bar>();
bar.add(new Bar());
List<IFoo> foo = bar.OfType<IFoo>().ToList<IFoo>();
这与列表的创建有关,您已指定T为IFoo,因此即使Bar支持IFoo,也不能将其实例化为Bar,因为它们是不同的类型。
我使用了一些Linq来使转换更加容易
List<Bar> bar = new List<Bar>();
bar.add(new Bar());
List<IFoo> foo = bar.Select(x => (IFoo)x).ToList();
相较于其他答案,它的描述稍显简洁,但效果良好。
List<IFoo>
的列表,你可以调用list.add(new Baz());
,假设Baz
实现了IFoo
。然而,你不能对List<Bar>
这样做,因此你不能在可以使用List<IFoo>
的任何地方使用List<Bar>
。Bar
实现了IFoo
,所以你可以在使用IFoo
的任何地方使用Bar
,因此当它期望一个IFoo
时,将Bar
传递给add
函数是有效的。IFoo
列表可能包含一些 Bar
,但 IFoo
列表并不等同于 Bar
列表。IFoo
列表可以包含一个 Bar
,因为 Bar
也是一个 IFoo
。这里我们谈论的是列表的元素。列表仍然是 IFoo
列表。我们没有改变这一点。foo
的列表仍然是 IFoo
列表(更严格地说,foo
被声明为 List<IFoo>
)。它不能是其他任何东西。特别是,它不能变成 Bar
列表(List<Bar>
)。Bar
列表是完全不同的对象,与 IFoo
列表不同。List<Bar>
不继承自 List<IFoo>