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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 13:56:58  来源:igfitidea点击:

C# List<Interface>: why you cannot do `List<IFoo> foo = new List<Bar>();`

c#generics

提问by newB

If you have an Interface IFooand 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.

//.....

myListis 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 Bazimplements 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 Barimplements 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 IFoos can contain some Bars as well, but a list of IFoos is notthe same thing as a list of Bars.

由于列表IFooS可包含一些BarS作为很好,但名单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 IFoos can contain a Bar, because a Baris an IFooas well. Here we're talking about the elements of the list. The list is still a list of IFoos. We haven't changed that.

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

Now, the list you called foois still a list of IFoos (more pedantically, foois declared as a List<IFoo>). It cannot be anything else. In particular, it cannot be made into a list of Bars (List<Bar>). A list of Baris a completely different object than a list of IFoos.

现在,您调用的列表foo仍然是IFoos的列表(更迂腐,foo声明为 a List<IFoo>)。它不可能是其他任何东西。尤其是不能做成Bars( List<Bar>)的列表。Bar列表与IFoos列表是完全不同的对象。

回答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

它比其他答案少一点冗长,但效果很好