Использование IReadOnlyCollection‹T› вместо IEnumerable‹T› для параметров, чтобы избежать возможного множественного перечисления

Мой вопрос связан с этим относительно использования IEnumerable<T> vs IReadOnlyCollection<T>.

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

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

 Foo[] arr = col as Foo[] ?? col.ToArray();

Тем не менее, я нахожу повторение этого кода загрязняющим окружающую среду, и я согласен с некоторыми источниками, что IReadOnlyCollection<T> является лучшей альтернативой, особенно с замечаниями, сделанными в эту статью, в которой говорится:

В последнее время я размышлял о достоинствах и недостатках возвращения IEnumerable<T>.

Положительным моментом является то, что интерфейс настолько минимален, насколько это возможно, поэтому он дает вам как автору метода больше гибкости, чем использование более тяжелой альтернативы, такой как IList<T> или (боже упаси) массив.

Однако, как я отметил в последнем сообщении возврат IEnumerable<T> побуждает вызывающих абонентов нарушать Принцип подстановки Лисков. Для них слишком просто использовать методы расширения LINQ, такие как Last() и Count(), чья семантика IEnumerable<T> не обещает.

Что необходимо, так это лучший способ заблокировать возвращенную коллекцию, не делая такие искушения столь заметными. (Мне вспоминается, как Барни Файф тяжело усвоил этот урок.)

Введите IReadOnlyCollection<T>, новое в .NET 4.5. . Он добавляет только одно свойство к IEnumerable<T>: свойство Count. Обещая подсчет, вы убеждаете своих абонентов, что ваш IEnumerable<T> действительно имеет конечную станцию. Затем они могут использовать методы расширения LINQ, такие как Last(), с чистой совестью.

Однако, как могли заметить наблюдатели, в этой статье говорится только об использовании IReadOnlyCollection<T> для возвращаемых типов. Мой вопрос: будут ли те же аргументы в равной степени применимы и к использованию его для параметров? Любые теоретические мысли или комментарии по этому поводу также будут оценены.

Фактически, я думаю, что общее эмпирическое правило использования IReadOnlyCollection<T> было бы там, где было бы возможно множественное перечисление (по отношению к предупреждению ReSharper), если используется IEnumerable<T>. В противном случае используйте IEnumerable<T>.


person Neo    schedule 21.12.2016    source источник
comment
В аннотациях resharper есть атрибут, называемый [NoEnumeration], ну, это просто атрибут, но там написано Indicates that IEnumerable, passed as parameter, is not enumerated., он ничего не делает, но я использовал его, потому что это круто   -  person M.kazem Akhgary    schedule 21.12.2016
comment
@M.kazemAkhgary, это круто и полезно, я думаю, где вы не перечисляете IEnumerable. Но мой вопрос шире, чем этот вариант использования, и больше о том, где перечисляется IEnumerable . Является ли IReadOnlyCollection<T> лучшей альтернативой в этих случаях по причинам, которые я упомянул (т. Е. По пунктам, сделанным в статье)?   -  person Neo    schedule 21.12.2016


Ответы (1)


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

person Neo    schedule 23.12.2016