I'm trying to return a List<List<string>> in a method that has a return type of IList<IList<string>>:
IList<IList<string>> Foo()
{
return new List<List<string>>();
}
However, I'm getting a compile error that says I can't convert List<List<string>> to IList<IList<string>>. I thought that since List<T> implements IList<T>, I should be able to return a List<List<string>> where an IList<IList<string>> is expected.
I've asked copilot about it and got answers about IList not being covariant or contravariant but I still can't wrap my mind around it. Return type of List<IList<string>> is valid and it confuses me.
Generic interface covariance means that we can substitute for T
a type that is the same or assignable to T
(in case of class hierarchy more derived, in case of interfaces - a class that implements the interface)
IList<T>
is not covariant. IEnumerable<out T>
is (notice the out
keyword)
For example, this would work fine with IEnumerable because we can substitute the generic parameter IList<string>
with List<string>
because the latter implements the IList<string>
interface.
IEnumerable<IList<string>> Foo() {
return new List<List<string>>();
}
However, with IList<T>
you need to substitute for the exact same T
.
So, if you need to stick to your example you can modify it to do this:
IList<IList<string>> Foo() {
return new List<IList<string>>();
}
and use it like this without issues
var foo = Foo();
foo.Add(new List<string>());
foo[0].Add("bar");
Console.WriteLine(foo[0][0]);