views:

178

answers:

5

I am trying to do this:

List<Parent> test = new List<Child>();

The complete code of my class is this:

class Program
{
    public static void Main(string[] args)
    {
        List<Parent> test = new List<Child>();

        test.Add(new Child());

        test.Add(new AnotherChild());
    }
}

class Parent { }

class Child : Parent { }

class AnotherChild : Parent { }

Can someebody please explian me why this gives me this error:

Error 2 Cannot convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List' d:\personal\documents\visual studio 2010\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs 20 24 ConsoleApplication3

And why does this work?

Parent[] test = new Child[10];
List<Parent> result = test.ToList();

Thanks :)

-- Right:

Now I know why: List is compiled to List`1 and List to List`2. And they have no relationship.

+4  A: 

Update: because the two types, List<Parent> and List<Child> is not co-variant.

Even though the generic parameter you pass in, Child, inherits Parent, the relationship is not carried into the closed List types. Thus, the resulting two List types are not interchangeable.

.Net 4.0 introduces co-variance/contra-variance. Your code will still not work with .Net 4.0 though, since neither the List class or the IList interface will be changed to be co-variant.

Peter Lillevold
+3  A: 

You can't do this because List<Child> isn't assignable to List<Parent>, even though Child is assignable to Parent. The List<T> type is invariant.

Is there any reason why you can't use something like this instead?

public static void Main(string[] args)
{
    List<Parent> test = new List<Parent>();

    test.Add(new Child());

    test.Add(new AnotherChild());
}
LukeH
This works, but I wanted to know the reason. Now I get it. Thanks.
Snake
A: 

Use this

 List<Parent> test = new List<Child>().Cast<Parent>().ToList();
Asad Butt
+1  A: 

Generics in C# are invariant, meaning there is no subtype relationship among the different instances of a generic type.

Conceptually speaking, List<Child> can not be a subtype of List<Parent>, because you can insert an instance of AnotherChild into a List<Parent>, but not into a List<Child>.

meriton
Note that in C# 4 there will be *limited* generic variance. It wouldn't make any difference in this case, but you would be able to convert from `IEnumerable<Child>` to `IEnumerable<Parent>`.
Jon Skeet
Interesting, I didn't know that. Thanks!
meriton
A: 

I advise you this artice (it has good description of covariance and contravariance.): http://blog.t-l-k.com/dot-net/2009/c-sharp-4-covariance-and-contravariance

Andrew Bezzub