1

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?

ryeguy
  • 65,519
  • 58
  • 198
  • 260
  • Duplicate? http://stackoverflow.com/questions/885893/how-to-make-a-generic-class-with-inheritance/885925 – kevindaub Jul 23 '09 at 02:19
  • Yeah, I figured this question was a dupe, it's just I didn't know what to search for this question as. – ryeguy Jul 23 '09 at 02:27
  • 4
    A list of giraffes is not a list of animals. Why? Because you can add a tiger to a list of animals, but not to a list of giraffes. Since the two types have different legal operations, you cannot convert one to the other. – Eric Lippert Jul 23 '09 at 05:23

5 Answers5

10

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
  • 236,483
  • 35
  • 423
  • 525
  • 3
    +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 Jul 23 '09 at 05:30
4

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
  • 35,734
  • 7
  • 75
  • 94
2

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
  • 733,204
  • 149
  • 1,241
  • 1,454
1

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
  • 11,940
  • 14
  • 50
  • 63
0

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
  • 7,199
  • 2
  • 30
  • 33