为什么我不能将IList 传递给F(IEnumerable )?

我想我可以将IList作为IEnumerable传递,因为ChildType列表中的每个对象显然也是ParentType的一个实例。 但我没有得到编译器的喜爱。 我错过了什么?

编辑:添加functionFoo3,它做我想要的。 谢谢!

 namespace StackOverflow { public class ParentClass { } public class ChildClass : ParentClass { } public class Test { // works static void Foo(ParentClass bar2) { } // fails static void Foo2(IEnumerable bar) { } // EDIT: here's the right answer, obtained from the // Charlie Calvert blog post static void Foo3(IEnumerable bar) where T : ParentClass { } public static void Main() { var childClassList = new List(); // this works as expected foreach (var obj in childClassList) Foo(obj); // this won't compile // Argument '1': cannot convert from // 'System.Collections.Generic.List' // to 'System.Collections.Generic.IEnumerable' Foo2(childClassList); // EDIT: this works and is what I wanted Foo3(childClassList); } } } 

因为generics不是共同变体:

Eric Lippert的博客上有一篇很棒的post。

Charlie Calvert的另一篇文章就在这里 。

您缺少通用方差,目前在C#中不存在。 我相信你的代码可以在C#4.0中运行。

这是其他问题的重复,但……

看到:

  • 为什么List不能存储在List变量中
  • 如何实现C#4.0通用协方差和Contra-Variance
  • 有没有办法将通用列表转换为接口/基类类型列表
  • C#.NET将一组InterfaceImplementingClass对象传递给一个采用Interface对象集合的例程
  • IEnumerableIEnumerable

您应该在Eric Lippert的Covariance和Contravariance系列中找到您所需要的一切。 这是一个相当多的阅读,但回答(a)为什么你不能在C#3.0中这样做,以及(b)为什么你能够在C#4.0上做到这一点。

我担心没有对通用参数类型的隐式转换(没有“generics方差”似乎是技术术语)。 不确定我能给你一个更深入的解释,但我会接受它作为CLR的工作方式……

您只需要在childClassList上使用Cast扩展方法将列表强制转换为IEnumerable。

虽然在IList和IEnumerable的情况下可以解决问题,但是当您将其视为集合和集合时,编译器无法真正了解它。

如果你可以使用集合作为集合,有人可以尝试添加一个父集合…编译器必须防止这种情况。