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:
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.