Есть ли у ICollection <T>заказ? - PullRequest
27 голосов
/ 06 января 2012

Следуя правилам, согласно которым публичные API никогда не должны возвращать список , я ослепляю, преобразуя весь код, который возвратил списки, чтобы вместо него возвращалось ICollection<T>:

public IList<T> CommaSeparate(String value) {...}

становится

public ICollection<T> CommaSeparate(String value) {...}

И хотя ICollection имеет Count, невозможно получить элементы по этому индексу.

И хотя ICollectionвыставляет перечислитель (разрешающий foreach), я не вижу никакой гарантии, что порядок перечисления начинается с «верха» списка, в отличие от «низа».

я мог бы смягчить это, избегаяиспользуйте ICollection, и вместо этого используйте Collection:

public Collection<T> Commaseparate(String value) {...}

Это позволяет использовать синтаксис Items[index].

К сожалению, моя внутренняя реализация создает массив;который я может привести к возвращению IList или ICollection, но не как Collection.

. Есть ли способы получить доступ к элементам коллекции в порядке?

Возникает более широкий вопрос: ICollection даже имеет ордер?


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

Концептуально, мне нужен контракт, который указывает «упорядоченный» набор кортежей строк.В случае контракта API, чтобы указать порядок, что из следующего является правильным:

IEnumerable<String> Grob(string s)

ICollection<String> Grob(string s)

IList<String> Grob(string s)

Collection<String> Grob(string s)

List<String> Grob(string s)

Ответы [ 9 ]

15 голосов
/ 06 января 2012

Интерфейс ICollection<T> ничего не определяет в заказе. Объекты будут в порядке, указанном возвращаемым объектом. Например, если вы вернете Values коллекцию SortedDictionary, объекты будут в порядке, определенном компаратором словаря.

Если вам нужен метод для возврата по контракту типа, для контракта которого требуется определенный порядок, вы должны указать это в сигнатуре метода, возвращая более конкретный тип.

Независимо от типа времени выполнения возвращаемого объекта, рассмотрите поведение, когда статическая ссылка равна IList<T> или ICollection<T>: когда вы вызываете GetEnumerator() (возможно, неявно в цикле foreach), вы будете вызывать тот же метод и получение того же объекта независимо от статического типа ссылки. Поэтому он будет вести себя одинаково независимо от типа возвращаемого значения CommaSeparate().

Дополнительная мысль:

Как кто-то еще указал, правило FXCop предостерегает от использования List<T>, а не IList<T>; вопрос, на который вы ссылаетесь, спрашивает, почему FXCop не рекомендует использовать IList<T> вместо List<T>, что является другим вопросом. Если я представлю, что вы анализируете строку командной строки, где важен порядок, я бы использовал IList<T> на вашем месте.

9 голосов
/ 06 января 2012

ICollection не имеет гарантированного порядка, но класс, который фактически его реализует, может (или не может).

Если вы хотите вернуть упорядоченную коллекцию, верните IList<T> и неслишком зацикливайтесь на общем здравом, но очень общем совете FxCop.

4 голосов
/ 06 января 2012

Нет, ICollection не подразумевает заказ.

3 голосов
/ 06 января 2012

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

3 голосов
/ 06 января 2012

ICollection - это просто интерфейс - нет никакой реализации или явной спецификации для заказа.Это означает, что если вы возвращаете что-то, что перечисляет упорядоченным образом, то, что потребляет, ваш ICollection будет делать это упорядоченным образом.

Порядок подразумевается только базовым, реализующим объект.В ICollection нет спецификации, которая гласит, заказывать или нет.Многократное перечисление по результату вызовет перечислитель базового объекта, который является единственным местом, где будут установлены эти правила.Объект не меняет способ перечисления только потому, что он наследует этот интерфейс.Если бы интерфейс указал , что это упорядоченный результат, то вы могли бы смело полагаться на упорядоченный результат реализующего объекта.

3 голосов
/ 06 января 2012

Экземпляр ICollection имеет "порядок" любого класса, который его реализует. То есть ссылка на List<T> как ICollection не изменит его порядок вообще.

Аналогично, если вы получаете доступ к неупорядоченной коллекции как ICollection, это также не навязывает порядок неупорядоченной коллекции.

Итак, на ваш вопрос:

Есть ли у ICollection заказ?

Ответ таков: он зависит исключительно от класса, который его реализует.

2 голосов
/ 06 января 2012

ICollection<T> - это просто интерфейс; упорядочен он или нет, полностью зависит от реализации, лежащей в его основе (которая должна быть непрозрачной).

Если вы хотите иметь доступ к нему по индексу, вы должны вернуть вещи как IList<T>, что равно IEnumerable<T> и ICollection<T>. Однако следует помнить, что в зависимости от базовой реализации для достижения произвольного элемента в коллекции в среднем может потребоваться время O (N / 2).

Я бы хотел полностью избежать интерфейсов 'collection' и вместо этого использовать пользовательский тип, представляющий коллекцию в терминах проблемной области и выставляющий соответствующие логические операции, подходящие для этого типа.

1 голос
/ 06 января 2012

Зависит от реализации экземпляра.ICollection, которая оказывается списком, имеет порядок, а ICollection - коллекцию.

Все ICollections реализуют IEnumerable, который возвращает элементы по одному, упорядоченно или нет.

РЕДАКТИРОВАТЬ: В ответ на ваш дополнительный пример разбора командной строки в вопросе, я бы сказал, что соответствующий тип возврата зависит от того, что вы делаете с этими аргументами впоследствии, но IEnumerable, вероятно, правильный.

Мое рассуждение состоит в том, что IList, ICollection и их конкретные реализации допускают изменение списка, возвращенного из Grob, что вам, вероятно, не нужно.Так как .NET не имеет интерфейса Indexed Sequence, IEnumerable - лучший выбор, чтобы запретить вашим вызывающим действиям что-то странное, например, попытаться изменить список параметров, которые они возвращают.

0 голосов
/ 18 декабря 2013

Если вы ожидаете, что все существующие и будущие версии вашего метода не будут иметь проблем с возвратом объекта, который сможет быстро и легко извлечь N-й элемент, используйте тип IList<T>, чтобы вернуть ссылку на что-то, что реализует оба IList<T> и не универсальный ICollection. Если вы ожидаете, что некоторые текущие или будущие версии не смогут быстро и легко вернуть N-й элемент, но смогут мгновенно сообщить количество элементов, используйте тип ICollection<T>, чтобы вернуть ссылку на что-то, реализующее ICollection<T>, и неуниверсальный ICollection. Если вы ожидаете, что у нынешней или будущей версий могут возникнуть проблемы, даже зная, сколько элементов существует, верните IEnumerable<T>. Вопрос последовательности не имеет значения; возможность доступа к N-му предмету подразумевает, что определенная последовательность существует, но ICollection<T> говорит о последовательности не больше и не меньше, чем IEnumerable<T>.

...