为什么我不能将IList <childtype>传递给F(IEnumerable <parenttype>)?</parenttype> </childtype>

时间:2009-03-10 21:41:53

标签: c#

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

编辑:添加功能Foo3,它做我想要的。谢谢!

namespace StackOverflow
{
    public class ParentClass
    {
    }

    public class ChildClass : ParentClass
    {
    }

    public class Test
    {
        // works
        static void Foo(ParentClass bar2)
        {
        }

        // fails
        static void Foo2(IEnumerable<ParentClass> bar)
        {
        }

        // EDIT: here's the right answer, obtained from the 
        // Charlie Calvert blog post 
        static void Foo3<T>(IEnumerable<T> bar) where T : ParentClass
        {
        }

        public static void Main()
        {
            var childClassList = new List<ChildClass>();

            // this works as expected
            foreach (var obj in childClassList)
                Foo(obj);

            // this won't compile
            // Argument '1': cannot convert from 
            // 'System.Collections.Generic.List<ChildClass>' 
            // to 'System.Collections.Generic.IEnumerable<ParentClass>' 
            Foo2(childClassList);

            // EDIT: this works and is what I wanted
            Foo3(childClassList);
        }
    }
}

5 个答案:

答案 0 :(得分:5)

因为泛型不是共同变体:

Eric Lippert's blog有一篇很棒的帖子。

来自Charlie Calvert is here的另一篇文章。

答案 1 :(得分:2)

答案 2 :(得分:1)

您应该在Eric Lippert's Covariance and Contravariance series中找到所需的全部内容。这是一个相当多的阅读,但回答(a)为什么你不能在C#3.0中这样做,以及(b)为什么你能够在C#4.0中做到这一点。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

虽然在IList和IEnumerable的情况下可以解决问题,但是当你把它看作收集和集合时,编译器无法真正知道它。

如果你可以使用集合作为集合,有人可以尝试在集合中添加一个父...编译器必须阻止它。