C# List<Interface>:为什么你不能做`List<IFoo> foo = new List<Bar>();`
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1228173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# List<Interface>: why you cannot do `List<IFoo> foo = new List<Bar>();`
提问by newB
If you have an Interface IFoo
and a class Bar : IFoo
, why can you do the following:
如果您有一个 InterfaceIFoo
和一个 class Bar : IFoo
,为什么可以执行以下操作:
List<IFoo> foo = new List<IFoo>();
foo.Add(new Bar());
But you cannot do:
但你不能这样做:
List<IFoo> foo = new List<Bar>();
采纳答案by Adam Robinson
At a casual glance, it appears that this should(as in beer shouldbe free) work. However, a quick sanity check shows us why it can't. Bear in mind that the following code will not compile. It's intended to show why it isn't allowed to, even though it looksalright up until a point.
乍一看,这似乎应该(就像啤酒应该是免费的)工作。但是,快速的健全性检查向我们展示了为什么它不能。请记住,以下代码将无法编译。它旨在说明为什么不允许这样做,即使它看起来不错。
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
is a List<IFoo>
, meaning it can take any instance of IFoo
. However, this conflicts with the fact that it was instantiated as List<Bar>
. Since having a List<IFoo>
means that I could add a new instance of Zed
, we can't allow that since the underlying list is actually List<Bar>
, which can't accommodate a Zed
.
myList
是 a List<IFoo>
,这意味着它可以采用 的任何实例IFoo
。但是,这与它被实例化为List<Bar>
. 由于有一种List<IFoo>
方法可以添加 的新实例Zed
,因此我们不能允许这样做,因为基础列表实际上是List<Bar>
,它不能容纳Zed
.
回答by Nathan
It is to do with the creation of the List, you have specified the T to be IFoo therefore you cannot instantiate it as a Bar since they are different types, even though Bar supports IFoo.
这与 List 的创建有关,您已将 T 指定为 IFoo,因此您无法将其实例化为 Bar,因为它们是不同的类型,即使 Bar 支持 IFoo。
回答by Dan Blair
List is the type in this case and it's not an inheritance question List<IFoo> really is different than List<Bar>. List doesn't know anythign of, or inherit the characteristics of either IFoo or Bar.
List 是这种情况下的类型,它不是继承问题 List<IFoo> 确实与 List<Bar> 不同。List 不知道或继承 IFoo 或 Bar 的任何特征。
Hope that helps.
希望有帮助。
回答by Amy B
List<Bar>
does not inherit from List<IFoo>
List<Bar>
不继承自 List<IFoo>
回答by sepp2k
If you have a list of type List<IFoo>
you can call list.add(new Baz());
assuming Baz
implements IFoo
. However you can't do that with a List<Bar>
, so you can't use a List<Bar>
everywhere you can use a List<IFoo>
.
如果你有一个类型列表,List<IFoo>
你可以调用list.add(new Baz());
假设Baz
工具IFoo
。但是你不能用 a 来做到这一点List<Bar>
,所以你不能在List<Bar>
任何可以使用 a的地方使用 a List<IFoo>
。
However since Bar
implements IFoo
, you can use a Bar everywhere you use IFoo
, so passing a Bar to add works when it expects and IFoo
.
但是,由于Bar
实现IFoo
,您可以在任何使用的地方使用 Bar IFoo
,因此在需要时传递 Bar 以添加作品 和IFoo
。
回答by Dustin Campbell
The reason is that C# does not support co- and contravariance for generics in C# 3.0 or earlier releases. This is being implemented in C# 4.0, so you'll be able to do the following:
原因是 C# 不支持 C# 3.0 或更早版本中的泛型的协变和逆变。这是在 C# 4.0 中实现的,因此您将能够执行以下操作:
IEnumerable<IFoo> foo = new List<Bar>();
Note that in C# 4.0, you can cast to IEnumerable<IFoo>, but you won't be be able cast to List<IFoo>. The reason is due to type safety, if you were able to cast a List<Bar> to List<IFoo> you would be able to add other IFoo implementors to the list, breaking type safety.
请注意,在 C# 4.0 中,您可以转换为 IEnumerable<IFoo>,但不能转换为 List<IFoo>。原因是由于类型安全,如果您能够将 List<Bar> 转换为 List<IFoo>,您将能够将其他 IFoo 实现器添加到列表中,从而破坏了类型安全。
For more background on covariance and contravariance in C#, Eric Lippert has a nice blog series.
有关 C# 中协变和逆变的更多背景信息,Eric Lippert 有一个不错的博客系列。
回答by Euro Micelli
Because a list of IFoo
s can contain some Bar
s as well, but a list of IFoo
s is notthe same thing as a list of Bar
s.
由于列表IFoo
S可包含一些Bar
S作为很好,但名单IFoo
小号不是一回事列表Bar
秒。
Note that I used English above instead of using C#. I want to highlight that this is not a deep problem; you are just getting confused by the details of the syntax. To understand the answer you need to see beyond the syntax and think about what it actually means.
请注意,我在上面使用了英语而不是使用 C#。我想强调的是,这不是一个深刻的问题;你只是对语法的细节感到困惑。要理解答案,您需要超越语法并考虑它的实际含义。
A list of IFoo
s can contain a Bar
, because a Bar
is an IFoo
as well. Here we're talking about the elements of the list. The list is still a list of IFoo
s. We haven't changed that.
IFoo
s的列表可以包含 a Bar
,因为 aBar
也是 an IFoo
。这里我们谈论的是列表的元素。该列表仍然是IFoo
s的列表。我们没有改变这一点。
Now, the list you called foo
is still a list of IFoo
s (more pedantically, foo
is declared as a List<IFoo>
). It cannot be anything else. In particular, it cannot be made into a list of Bar
s (List<Bar>
). A list of Bar
is a completely different object than a list of IFoo
s.
现在,您调用的列表foo
仍然是IFoo
s的列表(更迂腐,foo
声明为 a List<IFoo>
)。它不可能是其他任何东西。尤其是不能做成Bar
s( List<Bar>
)的列表。Bar
列表与IFoo
s列表是完全不同的对象。
回答by Adam Robinson
If you need to convert a list to a list of a base class or interface you can do this:
如果您需要将列表转换为基类或接口的列表,您可以这样做:
using System.Linq;
---
List<Bar> bar = new List<Bar>();
bar.add(new Bar());
List<IFoo> foo = bar.OfType<IFoo>().ToList<IFoo>();
回答by PatAttack
I used some linq to make the conversion easier
我使用了一些 linq 使转换更容易
List<Bar> bar = new List<Bar>();
bar.add(new Bar());
List<IFoo> foo = bar.Select(x => (IFoo)x).ToList();
It is a little less versbose than other answers but works well
它比其他答案少一点冗长,但效果很好