C#List <interface>:为什么你不能做`List <ifoo> foo = new List <bar>();`</bar> </ifoo> </interface>

时间:2009-08-04 15:29:17

标签: c# generics

如果您有界面IFoo和课程Bar : IFoo,为什么还要执行以下操作:

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

但你不能这样做:

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

9 个答案:

答案 0 :(得分:112)

随便看一眼,这个应该(如啤酒应该是免费的)工作。但是,快速的健全检查会告诉我们为什么不能这样做。请记住,以下代码将无法编译。它旨在说明为什么它不被允许,即使看起来直到一个点。

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>,不能容纳{{1} }}

答案 1 :(得分:38)

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

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

请注意,在C#4.0中,您可以强制转换为IEnumerable&lt; IFoo&gt;,但您无法转换为List&lt; IFoo&gt;。原因是由于类型安全,如果你能够施放List&lt; Bar&gt;列出&lt; IFoo&gt;你可以在列表中添加其他IFoo实现者,打破类型安全。

有关C#中协方差和逆变的更多背景知识,Eric Lippert有一个nice blog series

答案 2 :(得分:9)

如果需要将列表转换为基类或接口列表,可以执行以下操作:

using System.Linq;

---

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

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

答案 3 :(得分:4)

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

答案 4 :(得分:1)

List是这种情况下的类型,它不是继承问题List&lt; IFoo&gt;真的与List&lt; Bar&gt;不同。 List不知道任何标志,或继承IFoo或Bar的特征。

希望有所帮助。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

因为IFoo的列表也可以包含一些Bar,但IFoo s 的列表与列表不同 Bar s。

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

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

现在,您调用foo的列表仍然是IFoo的列表(更迂腐,foo被声明为List<IFoo>)。它不可能是其他任何东西。特别是,它不能成为Bar s(List<Bar>)的列表。 Bar列表与IFoo s列表完全不同。

答案 7 :(得分:1)

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

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

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

它比其他答案略显简洁,但运作良好

答案 8 :(得分:0)

如果您有List<IFoo>类型的列表,则可以致电list.add(new Baz());,假设Baz实施IFoo。但是,您无法使用List<Bar>执行此操作,因此无法在List<Bar>处使用List<IFoo>

但是,由于Bar实现了IFoo,您可以在使用IFoo的任何位置使用条形码,因此通过条形图添加可以在预期时使用IFoo