简体   繁体   中英

Why can't I pass IList<ChildType> to F(IEnumerable<ParentType>)?

I figured I could pass an IList<ChildClass> as an IEnumerable<ParentClass> , since obviously each object in a ChildType list is also an instance of ParentType. But I'm gettin no love from the compiler. What am I missing?

EDIT: Added function Foo3 which does what I want. Thanks!

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);
        }
    }
}

Because generics aren't co/contra variant:

Eric Lippert's blog has a great post on this.

Another article from Charlie Calvert is here .

You should find all you're looking for in Eric Lippert's Covariance and Contravariance series . It's a fair bit of reading, but answers (a) why you can't do this in C# 3.0, and (b) why you will be able to do it i C# 4.0.

I'm afraid there's no implicit casting to generic parameter types (no "generic variance" seems to be the technical term). Not sure I could give you a deeper explanation, but I would just accept it as the way the CLR works...

You'll simply need to use the Cast extension method on childClassList to cast the list to IEnumerable.

While in the case of IList and IEnumerable things would work out OK, the compiler has no way of really knowing that when you see it as collection and collection.

If you could use a collection as a collection somebody could try add a Parent to the collection... the compiler has to prevent this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM