Why can't List = List?

2020-02-07 07:15发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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

  • http://visualstudiomagazine.com/articles/2009/05/01/generic-covariance-and-contravariance-in-c-40.aspx
  • http://msdn.microsoft.com/en-us/library/ms173174(VS.80).aspx


回答4:

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.



回答5:

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.