Через какой интерфейс я должен выставлять список <T>через? - PullRequest
4 голосов
/ 28 мая 2009

В ответ на этот вопрос runefs предположил, что "если у вас нет очень конкретной причины для использования IList, вы должны рассмотреть IEnumerable". Что вы используете и почему?

Ответы [ 6 ]

12 голосов
/ 28 мая 2009

IEnumberable<T> только для чтения, вам необходимо восстановить коллекцию, чтобы внести в нее изменения. С другой стороны, IList<T> - чтение-запись. Поэтому, если вы ожидаете много изменений в коллекции, выставьте IList<T>, но если можно с уверенностью предположить, что вы не будете изменять его, перейдите с IEnumerable<T>.

7 голосов
/ 28 мая 2009

Всегда используйте наиболее ограниченный интерфейс, предоставляющий необходимые вам функции, потому что это дает вам максимальную гибкость для изменения реализации позже. Итак, если IEnumerable<T> достаточно, используйте это ... если вам нужны функции списка, используйте IList<T>.

И желательно использовать строго типизированные универсальные версии.

4 голосов
/ 28 мая 2009

Принцип, которому я следую, тот, который я прочитал некоторое время назад:

"Употребляй самое простое и выставляй самый сложный "

(Я уверен, что это действительно распространенное явление, и я неправильно цитирую его, если кто-то может знать источник, можете ли вы оставить комментарий или отредактировать, пожалуйста ...)

(Отредактировано, чтобы добавить - ну, вот я через пару недель, и я только что натолкнулся на эту цитату в совершенно ином контексте, похоже, она началась как Принцип устойчивости или Постель Закон -

Будьте консервативны в том, что вы делаете; будь либеральным в том, что ты принимаешь от других.

Первоначальное определение предназначено для сетевого взаимодействия через Интернет, но я уверен, что я видел его многоцелевым для определения классовых контрактов в ОО.)

По сути, если вы определяете метод для внешнего потребления, тогда параметры должны быть самым базовым типом, который дает вам требуемую функциональность - в случае вашего примера это может означать использование IEnumerable вместо IList. Это дает клиентскому коду максимальную гибкость по сравнению с тем, что он может передать. С другой стороны, если вы выставляете свойство для внешнего потребления, то делайте это с наиболее сложным типом (IList или ICollection вместо IEnumerable), так как это дает клиенту больше всего возможностей. гибкость в том, как они используют объект.


Я нахожу разговор между мной и DrJokepu в комментариях увлекательным, но я также ценю, что это не должен быть дискуссионный форум, поэтому я отредактирую свой ответ, чтобы дополнительно обрисовать причины своего выбора тенденция и предложить вам выставить его как IList (ну, на самом деле, список, как вы увидите). Скажем, это класс, о котором мы говорим:

public class Example
{
    private List<int> _internal = new List<int>();

    public /*To be decided*/ External
    {
        get { return _internal; }
    }
}

Итак, давайте сначала предположим, что мы выставляем External как IEnumerable. Причины, которые я видел для этого в других ответах и ​​комментариях, в настоящее время:

  • IEnumerable доступен только для чтения
  • IEnumerable является стандартом по умолчанию
  • Это уменьшает сцепление, так что вы можете изменить реализацию
  • Вы не раскрываете детали реализации

Хотя IEnumerable предоставляет только функции только для чтения, которые не делают его доступным только для чтения. Реальный тип, который вы возвращаете, легко узнать по рефлексии или просто приостановив отладчик и просмотрев, так что тривиально вернуть его обратно в List <>, то же самое относится к примеру FileStream в комментариях ниже. Если вы пытаетесь защитить участника, то притворяться, что это что-то другое, не способ сделать это.

Я не верю, что это стандарт де-факто. Я не могу найти никакого кода в библиотеке .NET 3.5, где у Microsoft была возможность вернуть конкретную коллекцию и вместо нее вернуть интерфейс. IEnumerable является более распространенным в 3.5 благодаря LINQ, но это потому, что они не могут предоставить более производный тип, а не потому, что они не хотят.

Теперь, уменьшая связь, с которой я согласен - до некоторой степени - в основном, этот аргумент, по-видимому, заключается в том, что вы говорите клиенту, что в то время, как возвращаемый вами объект представляет собой , список, который я хочу, чтобы вы рассматривали как IEnumerable на тот случай, если вы решите изменить внутренний код позже. Игнорирование проблем с этим и факта, что реальный тип все равно выставлен, оставляет вопрос «зачем останавливаться на IEnumerable?» если вы вернете его как тип объекта, у вас будет полная свобода изменить реализацию на что угодно! Это означает, что вы должны были принять решение о том, какой функциональности требует клиентский код, поэтому либо вы пишете клиентский код, либо решение основано на произвольных метриках.

Наконец, как уже говорилось ранее, вы можете предположить, что детали реализации всегда выставляются в .NET, особенно если вы публично выставляете объект.

Итак, после этой длинной диатрибы остался один вопрос - зачем выставлять его в виде списка <>? А почему бы не? Вы ничего не получили, выставив его как IEnumerable, так зачем же искусственно ограничивать способность клиентского кода работать с объектом? Представьте себе, если бы Microsoft решила, что коллекция Controls элемента управления Winforms должна отображаться как IEnumerable вместо ControlCollection - вы больше не сможете передавать его методам, которые требуют IList, работать с элементами с произвольным индексом или посмотреть, если он содержит определенный элемент управления, если вы не разыгрываете его. Microsoft на самом деле ничего не получила бы, и это доставило бы вам неудобства.

3 голосов
/ 28 мая 2009

Когда мне нужно только перечислить детей, я использую IEnumerable. Если мне понадобится граф, я использую ICollection. Я стараюсь избегать этого, потому что это раскрывает детали реализации.

2 голосов
/ 28 мая 2009

IList<T> действительно очень навороченный интерфейс. Я предпочитаю выставлять Collection<T> производные типы. Это в значительной степени соответствует тому, что предлагает Джеффри Рихтер (у вас нет книги рядом, поэтому не можете указать номер страницы / главы): методы должны принимать наиболее распространенные типы в качестве параметров и возвращать наиболее «производные» типы возвращаемые значения.

1 голос
/ 07 июня 2009

Если коллекция только для чтения предоставляется через свойство, то обычный способ сделать это - представить ее как ReadOnlyCollection (или ее производный класс), упаковывая все, что у вас есть. Он предоставляет клиенту полные возможности IList, и в то же время очень ясно дает понять, что он доступен только для чтения.

...