views:

311

answers:

5

Why won't the following code work?

class parent {}
class kid:parent {}

List<parent> parents=new List<kid>;

It seems obvious to me. What's going on here?

+9  A: 

C# does not currently support covariance.

It's coming in .NET 4.0, however, on interfaces and delegates.

Eric Lippert had a very nice series on this subject on his blog awhile back. Visual Studio Magazine covers it too in a recent article.

Jason
+1: Classic failure of the Liskov substitution principle. The proposed child is not generally substitutable for the proposed parent, therefore the inheritance is probably ill-conceived.
Greg D
+2  A: 

The feature you are looking for is called covariance. It is not supported in C# until version 4.0 and then only on interfaces and delegates.

Some links on the subject

JaredPar
A: 

As has been pointed out, this isn't currently supported in C#. In Java, arrays are covariant, and it can cause some problems. Consider your example, the actual list should be a list of "kid", meaning all the objects in it should be "kid"s (or "grandchildren"). But if the reference you're using to access the list is a list of "parent" then you could insert a "parent" into the list which obviously shouldn't happen.

Tal Pressman
+2  A: 

Besides the lack of generic variance support in C# prior to version 4.0, List is mutable and so cannot safely be covariant. Consider this:

void AddOne<T>(List<T> arg) where T : new()
{
    arg.Add(new T());
}

void Whoops()
{
    List<parent> contradiction = new List<kid>();
    AddOne(contradiction);  // what should this do?
}

This would attempt to add a Parent to a List referenced via a List reference, which is not safe. Arrays are permitted to be covariant by the runtime, but are type-checked at mutation time and an exception is thrown if the new element is not assignable to the array's runtime element type.

Jeffrey Hantin
+1. Good explanation of why this is a bad idea.
Daniel Pryden
A: 

If you know that the List<Parent> contains List<child> you can use an extension method to 'convert', (really just take the Parents that ARE of type child and return them in a list. eg something like:

  public static List<T> Convert<T, T2>(this List<T2> input) {
      return input.OfType<T>().ToList();
    }

Im not sure if this helps you, but my 2 cents worth! I use it quite alot.

theringostarrs