Когда я пишу свой DAL или другой код, который возвращает набор элементов, должен ли я всегда делать оператор return:
public IEnumerable<FooBar> GetRecentItems()
или
public IList<FooBar> GetRecentItems()
В настоящее время в моем коде я стараюсь использовать IEnumerable как можно чаще, но я не уверен, что это лучшая практика? Это казалось правильным, потому что я возвращал наиболее общий тип данных, все еще описывая то, что он делает, но, возможно, это неправильно.
c#
ienumerable
КорольНестор
источник
источник
Ответы:
Это действительно зависит от того, почему вы используете этот конкретный интерфейс.
Например,
IList<T>
есть несколько методов, которых нет вIEnumerable<T>
:IndexOf(T item)
Insert(int index, T item)
RemoveAt(int index)
и свойства:
T this[int index] { get; set; }
Если вам как-то нужны эти методы, то непременно вернитесь
IList<T>
.Кроме того, если метод, который использует вашIEnumerable<T>
результат, ожидаетIList<T>
, он избавит CLR от рассмотрения любых необходимых преобразований, тем самым оптимизируя скомпилированный код.источник
В руководящих принципах разработки фреймворка рекомендуется использовать коллекцию классов, когда вам нужно вернуть коллекцию, которая может быть изменена вызывающей стороной или ReadOnlyCollection. для коллекций только для чтения.
Причина, по которой это предпочтительнее простого,
IList
заключается в том, чтоIList
, что вызывающему абоненту не сообщается, доступен он только для чтения или нет.Если вы вернете
IEnumerable<T>
вместо этого, некоторые операции могут быть немного сложнее для вызывающего. Кроме того, вы больше не дадите вызывающему абоненту возможность изменять коллекцию, чего вы можете или не хотите.Имейте в виду, что LINQ содержит несколько уловок в рукаве и оптимизирует определенные вызовы в зависимости от типа, для которого они выполняются. Так, например, если вы выполните
Count
а базовая коллекция - это List, он НЕ будет проходить через все элементы.Лично для ORM я бы, вероятно, остановился
Collection<T>
на возвращаемом значении.источник
В общем, вам следует требовать наиболее общие и возвращать наиболее конкретные вещи, которые вы можете. Итак, если у вас есть метод, который принимает параметр, и вам действительно нужно только то, что доступно в IEnumerable, тогда это должен быть ваш тип параметра. Если ваш метод может возвращать IList или IEnumerable, предпочтительнее возвращать IList. Это гарантирует, что его сможет использовать самый широкий круг потребителей.
Будьте свободны в том, что вам нужно, и четко указывайте, что вы предоставляете.
источник
Это зависит...
Возврат наименее производного типа (
IEnumerable
) предоставит вам наибольшую свободу действий для изменения базовой реализации в будущем.Возврат более производного типа (
IList
) предоставляет пользователям вашего API больше операций над результатом.Я всегда предлагаю возвращать наименее производный тип, который имеет все операции, которые потребуются вашим пользователям ... так что в основном вы должны сначала определить, какие операции с результатом имеют смысл в контексте определяемого вами API.
источник
Следует учитывать, что если вы используете оператор LINQ с отложенным выполнением для создания своего
IEnumerable<T>
, вызов.ToList()
перед возвратом из вашего метода означает, что ваши элементы могут повторяться дважды - один раз для создания списка и один раз, когда вызывающий цикл проходит через , фильтрует или преобразует возвращаемое значение. На практике я предпочитаю избегать преобразования результатов LINQ-to-Objects в конкретный список или словарь до тех пор, пока мне это не понадобится. Если моему вызывающему абоненту нужен List, это можно сделать одним простым вызовом метода - мне не нужно принимать это решение за них, и это делает мой код немного более эффективным в тех случаях, когда вызывающий просто выполняет foreach.источник
List<T>
предлагает вызывающему коду гораздо больше возможностей, таких как изменение возвращаемого объекта и доступ по индексу. Итак, вопрос сводится к следующему: в конкретном случае использования вашего приложения ХОТИТЕ ли вы поддерживать такое использование (предположительно, возвращая только что созданную коллекцию!) Для удобства вызывающего абонента - или вам нужна скорость для простого случая, когда все вызывающей стороне необходимо пройти через коллекцию, и вы можете безопасно вернуть ссылку на реальную базовую коллекцию, не опасаясь, что это приведет к ее ошибочным изменениям и т. д.?Только вы можете ответить на этот вопрос, и только хорошо понимая, что ваши абоненты захотят делать с возвращаемым значением и насколько важна здесь производительность (насколько велики коллекции, которые вы копируете, насколько вероятно, что это будет узким местом, и т.д).
источник
Если коллекция предназначена только для чтения или модификация коллекции контролируется,
Parent
то возвращениеIList
только дляCount
не является хорошей идеей.В Linq есть
Count()
метод расширения, дляIEnumerable<T>
которого внутри CLR будет ярлык,.Count
если базовый тип имеет типIList
, поэтому разница в производительности незначительна.Как правило, я считаю (мнение), что лучше возвращать IEnumerable, где это возможно, если вам нужно делать дополнения, затем добавьте эти методы в родительский класс, иначе потребитель затем управляет коллекцией в модели, которая нарушает принципы, например,
manufacturer.Models.Add(model)
нарушает закон Деметра. Конечно, это всего лишь рекомендации, а не жесткие и быстрые правила, но до тех пор, пока вы полностью не поймете их применимость, лучше слепо следовать, чем не следовать вовсе.(Примечание: при использовании nNHibernate вам может потребоваться сопоставление с частным IList с использованием разных аксессоров.)
источник
Не все так просто, когда речь идет о возвращаемых значениях, а не о входных параметрах. Когда это входной параметр, вы точно знаете, что вам нужно делать. Итак, если вам нужно иметь возможность перебирать коллекцию, вы берете IEnumberable, тогда как если вам нужно добавить или удалить, вы берете IList.
В случае с возвращаемым значением сложнее. Чего ожидает ваш собеседник? Если вы вернете IEnumerable, он априори не будет знать, что может сделать из него IList. Но если вы вернете IList, он будет знать, что может перебирать его. Итак, вы должны принять во внимание, что ваш вызывающий абонент собирается делать с данными. Функциональность, которую ваш вызывающий абонент ожидает, - это то, что должно регулировать при принятии решения о том, что вернуть.
источник
как все уже говорили, это зависит от обстоятельств, если вы не хотите добавлять / удалять функциональность на вызывающем уровне, тогда я буду голосовать за IEnumerable, поскольку он обеспечивает только итерацию и базовую функциональность, которые в предполагаемом дизайне мне нравятся. Возвращаясь к IList, мои голоса всегда повторяются, но в основном это то, что вам нравится, а что нет. с точки зрения производительности я думаю, что они больше похожи.
источник
Если вы не учитываете в своем внешнем коде, всегда лучше вернуть IEnumerable, потому что позже вы можете изменить свою реализацию (без воздействия внешнего кода), например, для логики итератора yield и сохранения ресурсов памяти (кстати, очень хорошая языковая функция ).
Однако, если вам нужно количество элементов, не забывайте, что между IEnumerable и IList есть еще один уровень - ICollection .
источник
Я могу быть здесь немного не в своей тарелке, поскольку пока никто этого не предлагал, но почему бы вам не вернуть
(I)Collection<T>
?Насколько я помню, это
Collection<T>
был предпочтительный тип возвращаемого значения,List<T>
потому что он абстрагирует реализацию. Все они реализованыIEnumerable
, но для меня это звучит слишком низко для работы.источник
Я думаю, вы можете использовать и то, и другое, но у каждого есть применение. В основном
List
есть,IEnumerable
но у вас есть функция подсчета, Добавить элемент, удалить элементIEnumerable
неэффективен для подсчета элементов или получения определенного элемента в коллекции.List
- это коллекция, которая идеально подходит для поиска определенных элементов, простого добавления или удаления элементов.Обычно я стараюсь использовать
List
там, где это возможно, поскольку это дает мне больше гибкости.Используйте,
List<FooBar> getRecentItems()
а неIList<FooBar> GetRecentItems()
источник
Я думаю, что общее правило - использовать более конкретный класс для возврата, чтобы избежать ненужной работы и дать вашему вызывающему абоненту больше возможностей.
Тем не менее, я думаю, что важнее рассмотреть код перед вами, который вы пишете, чем код, который напишет следующий парень (в пределах разумного). Это потому, что вы можете делать предположения относительно кода, который уже существует.
Помните, что перемещение UP к коллекции из IEnumerable в интерфейсе будет работать, переход к IEnumerable из коллекции приведет к нарушению существующего кода.
Если эти мнения кажутся противоречивыми, то это потому, что решение субъективно.
источник
TL; DR; - резюме
List
) для возвращаемых значений и наиболее общий тип для входных параметров даже в случае коллекций.IReadOnlyList
илиIReadOnlyCollection
в качестве типа возвращаемого значения.Больше
источник