Just do this:
return new List<IList<T>>();
Because List<T>
implements IList<T>
, you will be able to add any kind of IList<T>
to the result. For example:
Foo<int>().Add(new List<int>());
As to the why, this is a matter of covariance/contravariance (I always get the two mixed up). Basically, if you say you're returning an IList<IList<T>>
, then someone should be able to add any kind of IList<T>
to the result:
Foo<int>().Add(new []{1}); // arrays implement `IList`
Obviously if you had returned a List<List<T>>
then the above line of code wouldn't work: you would be attempting to add a T[]
to the collection of List<T>
. So even though a List<T>
is an IList<T>
, a List<List<T>>
is not an IList<IList<T>>
.
Note: This next portion only applies to .NET 4 and up, as that was the first version to support covariance and contravariance in interfaces.
On the other hand, if you know that the person consuming your result isn't planning to add anything to the list, but is only trying to iterate across it, you could change your return type to IEnumerable<IList<T>>
and then it would be perfectly fine to return a List<List<T>>
. Why? Because the IEnumerable<T>
interface is covariant:
public interface IEnumerable<out T>
That "out" tells the compiler that this interface will only have methods that return values related to T
(like GetEnumerator
), and it won't have any methods that take something related to T
as a parameter (like Add
).