I'm working on some problems on Leetcode and coding in C#, and problems which require a collection of collections require a return type of IList<IList<<int>>.
I am failing to understand why I get the following error, when I return a type of List<List<int>> :
error CS0266: Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List>' to 'System.Collections.Generic.IList<System.Collections.Generic.IList>'. An explicit conversion exists (are you missing a cast?) (in Solution.cs)
List<T> implements IList<T>...so why is it that I am getting such errors?
I've also tried instantiating an IList<List<T>> and I get the same type of error as well. I'm genuinely confused. It seems there is something that I am failing to understand correctly about the type parameters for this generic type.
CodePudding user response:
If you have a list
List<List<int>> listOfLists = new List<List<int>>();
and you have some IList<int> someList
you can't do this
listOfLists.Add(someList);
because listOfLists
is expecting List<int>
as an input. Basically you can implicitly convert List<int>
to IList<int>
for output, but you can't implicitly convert IList<int>
to List<int>
for input
What you can do is just define your original list as IList<IList<int>>
IList<IList<int>> listOfLists = new List<IList<int>>();
and you can add List<int>
or IList<int>
to that list and return it matching your required output.
CodePudding user response:
The way how type arguments of generics work is sometimes counterintuitive and different from language to language.
Suppose that you have a generic type G<T>
and two types A
and A1
. Now, supposing that A1
derives from A
, this does not imply that G<A1>
is a subtype of G<A>
!
The reason behind this is a type safety concept called variance and, for this particular case, invariance. In simple words, the only subtype of G<A>
is G<A>
itself.
To relate the general rule above to your scenario, G<T>
is IList<T>
(the outer one), A
is IList<int>
(the inner one) and A1
is List<int>
.
To solve your issue, instead of declaring and IList<List<T>>
as you said in the last paragraph of your question, you may declare and return a List<IList<T>>
(note: swapped with respect to your declaration) or even directly a IList<IList<T>>
.
Finally, keep in mind that, even if the error message talks about a missing cast, there should be no need for any casts and everything can be solved type-safely.
If you could provide the snippet that has the error, I can point out more concretely where the issue is and what's the cleanest solution.