Использование типа IEnumerable <T>в параметре метода - PullRequest
4 голосов
/ 31 марта 2012

Ранее я использовал тип IEnumerable<T>, если в качестве параметра метода передал коллекцию.

Но недавно у меня возникла проблема с коллекцией типа IEnumerable<T>, которая была создана аналогичным образом:

var peoples = names.Select(name => new People(name));

В этом случае всегда, если я использую коллекцию people (например, foreach), он создает новый экземпляр класса People и может легко вызвать ошибку.

Поэтому я хочу спросить, правильно ли использовать параметр типа IEnumerable <T>. Я думаю, что это может вызвать проблемы (см. Пример выше), и этот тип не должен использоваться. Какие альтернативы вы рекомендуете (ICollection<T>, IList<T> и т. Д.) И когда использовать какую альтернативу?

Или вы думаете, что это глупый вопрос, потому что для создания объектов в методе Select используется только дурак?

Конечно, я знаю, что могу использовать ToArray() или ToList() и, таким образом, решить проблему. Но кто-то еще, кто использует этот метод, может не знать. Я хотел бы знать, как предотвратить это, выбрав правильный параметр типа. Список или массив слишком специфичны для меня, когда я хочу просто «перечислить» объекты.

Ответы [ 2 ]

7 голосов
/ 31 марта 2012

IEnumerable не является коллекцией.Это просто то, что вы можете «перечислить».Проблема не в том, что IEnumerable передается в ваш метод, проблема в том, что если вы используете LINQ (Select метод), каждый раз, когда вы читаете перечислимое, он снова выполняет код.Если вы хотите выполнить его только один раз, вы можете использовать методы ToArray() или ToList():

var peoples = names.Select(name => new People(name)).ToList();

Таким образом, вы все равно можете передать его любому методу, принимающему IEnumerable (или List) и он будет создавать только один экземпляр для каждого человека.

Редактировать: Ваш метод не должен беспокоиться о подобных проблемах.Это проблема звонящих.Могут быть вполне веские причины для вызова вашего метода с перечислимым вместо списка.Вызывающий должен знать, что перечислимый дает разные результаты, если он передает его разным методам, поэтому вам не следует об этом беспокоиться.

Единственное исключение - это если вы перечисляете параметр более одного раза в самом методе.В этом случае вы должны кэшировать параметр в списке внутри метода, а затем перечислять список столько раз, сколько вам нужно.

2 голосов
/ 31 марта 2012

Предложения ToArray и ToList раскрывают нечто большее, чем можно было бы изначально представить.Мы склонны думать, что этот совет просто говорит, что вызов ToList / ToArray либо на сайте вызова, либо в первую очередь в вашем методе исправляет проблему, но ваш вопрос в том, подходит ли IEnumerable<T> - выможет измениться с типа параметра с IEnumerable<T> на что-то другое (например, ICollection<T>), что возлагает ответственность на вызывающего, чтобы преобразовать во что-то, реализующее этот интерфейс (обратите внимание, что T[], List<T>, IList<T> и Collection<T> все делают).Часть проблемы с этим подходом состоит в том, что эти интерфейсы представляют изменяемые коллекции, тогда как IEnumerable<T> объявляет, что метод перечисляет элементы - только одна из причин, почему мне не нравится этот подход.

Что если потенциальная ошибкана самом деле не было ошибки?Возможно, вызывающий объект хочет, чтобы это были защитные копии или объекты с тупыми данными - в этих последних случаях это может быть неэффективно в некоторой мере, но он требует от них сделать копию - но в этом предлагаемом использовании это определенно не ошибка.Точно так же, один размер подходит всем рекомендациям, не подходит, потому что IEnumerable<T> объекты не должны когда-либо заканчиваться - но требование передачи типа массива будет означать, что бесконечный (то есть вычисляемый) или просто большой IEnumerable<T>об объектах не может быть и речи.

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

Перефразируя цитату:

Проблема с проектированием для предотвращения проблем, которые будут создавать идиоты, заключается в том, что идиоты настолько чертовски гениальны.

Надеюсь, это поможет.Ура!

...