简体   繁体   中英

How to use polymorphism with a list of lists in C#

I am having trouble using polymorphism with a list of lists of int in C#. I need the "external" list to be able to add/remove "internal" lists, but the "internal" lists don't need to change. So I thought about using a variable type ICollection<IEnumerable<int>> . Now, I now that this works:

IEnumerable<int> someList = new List<int>(); //Works fine

And I also now that this works:

ICollection<int> anotherList = new List<int>(); //Also works fine

However, I was surprised to know that this throws a compilation error:

ICollection<IEnumerable<int>> listOfLists = new List<List<int>>(); //Doesn't compile

Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List>' to 'System.Collections.Generic.ICollection<System.Collections.Generic.IEnumerable>'. An explicit conversion exists (are you missing a cast?)

And I was also surprised to find out that this DOES compile fine:

IEnumerable<ICollection<int>> anotherListOfLists = new List<List<int>>(); //Works fine (?)

I know that a simple List<List<int>> listOfListsWithoutPolymorphism = new List<List<int>>(); would work, but my questions are:

  1. What are the differences between the 3rd and the 4th examples?
  2. How could I implement what I need (something like ICollecion<IEnumerable<int>> ) using polymorphism?

This is to do with variance of the actual interface and not the variance of what the interface implements.

Let's refresh:

  • Covariance permits a method to have a more derived return type than that defined by the generic type parameter of the interface

  • Inversely, an invariant interface doesn't allow a more derived type

The interface signatures in your example:

public interface IEnumerable<out T> : IEnumerable {}

public interface ICollection<T> : IEnumerable<T> {}

Let's make easier to see with a contrived example:

public interface ICovariant<out T> { }

public interface IInvariant<T> : ICovariant<T> { }

public class SomeClass<T> : IInvariant<T> { }

Tests

// works because `SomeClass` implements IInvariant, type parameters are the same
IInvariant<int> test1 = new SomeClass<int>(); 

// works because SomeClass implements IInvariant which implements ICovariant, type parameters are the same
ICovariant<int> test2 = new SomeClass<int>();

// works because SomeClass implements IInvariant, type parameters are the same
IInvariant<ICovariant<int>> test3 = new SomeClass<ICovariant<int>>();

// works because IInvariant implements ICovariant, type parameters are the same
ICovariant<IInvariant<int>> test4 = new SomeClass<IInvariant<int>>();

// works because ICovariant is covariant and SomeClass implements IInvariant
// remembering Covariance permits a more derived type 
ICovariant<IInvariant<int>> test6 = new SomeClass<SomeClass<int>>();

// hold up, this does not work
// IInvariant is invariant and the type parameters are different!
// an Invariant interface doesn't allow a more derived type
IInvariant<ICovariant<int>> test5 = new SomeClass<SomeClass<int>>();

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