Через какой интерфейс я должен выставлять List<T> через?
6 ответов
IEnumberable<T>
только для чтения, вы должны восстановить коллекцию, чтобы внести в нее изменения. С другой стороны, IList<T>
это чтение-запись. Так что если вы ожидаете много изменений в коллекции, выставьте IList<T>
но если можно с уверенностью предположить, что вы не будете изменять его, перейдите с IEnumerable<T>
,
Всегда используйте наиболее ограниченный интерфейс, предоставляющий необходимые вам функции, потому что это дает вам максимальную гибкость для изменения реализации позже. Так что если IEnumerable<T>
достаточно, тогда используйте это... если вам нужны списочные функции, используйте IList<T>
,
И желательно использовать строго типизированные универсальные версии.
Принцип, которому я следую, тот, который я прочитал некоторое время назад:
"Потребляй самое простое и выставляй самое сложное"
(Я уверен, что это действительно распространено, и я неправильно цитирую это, если кто-то может знать источник, можете ли вы оставить комментарий или отредактировать, пожалуйста...)
(Отредактировано, чтобы добавить - ну, я здесь пару недель спустя, и я только что натолкнулся на эту цитату в совершенно ином контексте, похоже, она началась как Принцип устойчивости или Закон Постеля -
Будьте консервативны в том, что вы делаете; быть либеральным в том, что вы принимаете от других.
Первоначальное определение предназначено для сетевого взаимодействия через Интернет, но я уверен, что я видел его многоцелевым для определения классовых контрактов в ОО.)
По сути, если вы определяете метод для внешнего потребления, тогда параметры должны быть самым базовым типом, который дает вам необходимую функциональность - в случае вашего примера это может означать использование 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 - это стандарт defacto
- Это уменьшает сцепление, так что вы можете изменить реализацию
- Вы не раскрываете детали реализации
В то время как IEnumerable предоставляет только функциональность только для чтения, которая не делает его доступным только для чтения. Реальный тип, который вы возвращаете, легко узнать по рефлексии или просто приостановив отладчик и просмотрев, так что тривиально вернуть его обратно в List<>, то же самое относится к примеру FileStream в комментариях ниже. Если вы пытаетесь защитить участника, то притворяться, что это что-то другое, не способ сделать это.
Я не верю, что это стандарт де-факто. Я не могу найти никакого кода в библиотеке.NET 3.5, где у Microsoft была возможность вернуть конкретную коллекцию и вместо нее вернуть интерфейс. IEnumerable более распространен в 3.5 благодаря LINQ, но это потому, что они не могут предоставлять более производный тип, а не потому, что они этого не хотят.
Теперь, уменьшая связь, с которой я согласен - до некоторой степени - в основном этот аргумент, по-видимому, заключается в том, что вы говорите клиенту, что, хотя возвращаемый вами объект является списком, который я хочу, чтобы вы рассматривали, как IEnumerable, на случай, если вы решите изменить внутренний код позже. Игнорирование проблем с этим и тот факт, что реальный тип все равно выставлен, оставляет вопрос "зачем останавливаться на IEnumerable?" если вы вернете его как тип объекта, у вас будет полная свобода изменить реализацию на что угодно! Это означает, что вы должны были принять решение о том, какой функциональности требует клиентский код, поэтому либо вы пишете клиентский код, либо решение основано на произвольных метриках.
Наконец, как уже говорилось ранее, вы можете предположить, что детали реализации всегда предоставляются в.NET, особенно если вы публикуете объект публично.
Итак, после этой длинной диатрибы остался один вопрос - зачем выставлять его в виде списка <>? А почему бы не? Вы ничего не получили, выставив его как IEnumerable, так зачем же искусственно ограничивать способность клиентского кода работать с объектом? Представьте себе, если бы Microsoft решила, что коллекция Controls элемента управления Winforms должна отображаться как IEnumerable вместо ControlCollection - вы больше не сможете передавать его методам, требующим IList, работать с элементами с произвольным индексом или смотреть, если он содержит определенный элемент управления, если вы не разыгрываете его. Microsoft на самом деле ничего не получила бы, и это только доставило бы вам неудобства.
Когда мне нужно только перечислить детей, я использую IEnumerable. Если мне понадобится граф, я использую ICollection. Я стараюсь избегать этого, потому что это раскрывает детали реализации.
IList<T>
действительно очень навороченный интерфейс. Я предпочитаю выставлять Collection<T>
Типы Это в значительной степени согласуется с тем, что предлагает Джеффри Рихтер (нет книги рядом, поэтому нельзя указывать номер страницы / главы): методы должны принимать наиболее распространенные типы в качестве параметров и возвращать наиболее "производные" типы как возвращаемые значения
Если коллекция только для чтения предоставляется через свойство, то обычный способ сделать это - представить ее как ReadOnlyCollection (или ее производный класс), оборачивая все, что у вас есть. Он предоставляет клиенту полные возможности IList, и в то же время очень ясно дает понять, что он доступен только для чтения.