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

如果你有一个接口IFoo和一个Bar : IFooBar : 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

原因是C#不支持C#3.0或更早发行版中的generics和协变性。 这是在C#4.0中实现的,所以你可以做到以下几点:

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

请注意,在C#4.0中,您可以强制转换为IEnumerable <IFoo>,但不能强制转换为List <IFoo>。 原因是由于types安全性,如果您能够将List <Bar>转换为List <IFoo>,则可以将其他IFoo实现者添加到列表中,从而打破types安全性。

有关C#中协变和逆变的更多背景,Eric Lippert有一个很好的博客系列 。

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

 using System.Linq; --- List<Bar> bar = new List<Bar>(); bar.add(new Bar()); List<IFoo> foo = bar.OfType<IFoo>().ToList<IFoo>(); 

这是创build列表,你已经指定T为IFoo,因此你不能将它实例化为一个Bar,因为它们是不同的types,即使Bar支持IFoo。

List是这种情况下的types,它不是一个inheritance问题List <IFoo>确实不同于List <Bar>。 列表不知道任何关系,或者inheritanceIFoo或Bar的特性。

希望有所帮助。

因为IFoo的列表也可以包含一些Bar ,但是IFoo的列表与Bar列表不是一回事。

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

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

现在,你称为foo的列表仍然是IFoo的列表(更迂回地说, foo被声明为List<IFoo> )。 它不能是其他的东西。 特别是,它不能被制作成BarList<Bar>List<Bar> )。 Bar列表与IFoo列表完全不同。

List<Bar>不会从List<IFoo>inheritance

如果你有一个List<IFoo>types的List<IFoo>你可以调用list.add(new Baz()); 假设Baz实施IFoo 。 然而,你不能用List<Bar>来做到这一点,所以你不能在任何你可以使用List<IFoo>地方使用List<Bar> List<IFoo>

然而,因为Bar实现了IFoo ,所以你可以在任何你使用IFoo地方使用Bar,所以当它期望和IFoo时,通过一个Bar来添加工作。

我使用了一些linq来使转换更容易

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

这比其他答案less一点,但效果很好