Просто сделайте это:
return new List<IList<T>>();
Поскольку List<T>
реализует IList<T>
, вы сможете добавить любой результат IList<T>
к результату.Например:
Foo<int>().Add(new List<int>());
Что касается , почему , это вопрос ковариации / контравариантности (я всегда смешиваю два).По сути, если вы говорите , что вы возвращаете IList<IList<T>>
, тогда кто-то должен иметь возможность добавить к результату любой вид IList<T>
:
Foo<int>().Add(new []{1}); // arrays implement `IList`
Очевидно, что если у вас быловернул List<List<T>>
, тогда приведенная выше строка кода не сработает: вы попытаетесь добавить T[]
в коллекцию List<T>
.Таким образом, даже если List<T>
является IList<T>
, List<List<T>>
не является IList<IList<T>>
.
Примечание. Следующая часть относится только к .NET 4 и выше, так какпервая версия для поддержки ковариации и контравариантности в интерфейсах.
С другой стороны, если вы знаете, что человек, использующий ваш результат, не планирует добавлять что-либо в список, а только пытаетсяитерируя по нему, вы можете изменить тип возвращаемого значения на IEnumerable<IList<T>>
, и тогда было бы прекрасно вернуть List<List<T>>
.Зачем?Поскольку интерфейс IEnumerable<T>
является ковариантным :
public interface IEnumerable<out T>
Этот "out" говорит компилятору, что этот интерфейс будет иметь только методы, которые возвращают значения, относящиеся к T
(например, GetEnumerator
), и у него не будет методов, которые принимают в качестве параметра что-то, связанное с T
(например, Add
).