Возвращение IList - PullRequest
       8

Возвращение IList

6 голосов
/ 16 ноября 2011

У меня есть метод, который создает списки списков.Я хотел бы, чтобы возвращаемый тип использовал общий интерфейс IList <>, чтобы уменьшить связь с конкретным типом List <> в нисходящем направлении.Однако компилятор борется с преобразованием типов.

public IList<IList<T>> Foo<T>()
    {
        return new List<List<T>>();
    } 

Почему это не работает, когда это работает:

public IList<T> Foo<T>()
    {
        return new List<T>();
    } 

Какой самый элегантный выход из этого беспорядка?

Ответы [ 2 ]

13 голосов
/ 16 ноября 2011

Просто сделайте это:

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

1 голос
/ 16 ноября 2011

Это связано с C # ковариацией и контравариантностью. Вы можете прочитать больше здесь .

Чтобы сделать интерфейс интерфейса T, ваши интерфейсы должны быть помечены как out T или T. IEnumerable помечен как out T.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...