为什么我不能将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对象集合的例程
- 从
IEnumerable
为IEnumerable
您应该在Eric Lippert的Covariance和Contravariance系列中找到您所需要的一切。 这是一个相当多的阅读,但回答(a)为什么你不能在C#3.0中这样做,以及(b)为什么你能够在C#4.0上做到这一点。
我担心没有对通用参数类型的隐式转换(没有“generics方差”似乎是技术术语)。 不确定我能给你一个更深入的解释,但我会接受它作为CLR的工作方式……
您只需要在childClassList上使用Cast扩展方法将列表强制转换为IEnumerable。
虽然在IList和IEnumerable的情况下可以解决问题,但是当您将其视为集合和集合时,编译器无法真正了解它。
如果你可以使用集合作为集合,有人可以尝试添加一个父集合…编译器必须防止这种情况。