Вопрос по c# – Должен ли я всегда возвращать IEnumerable вместо IList ?

87

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

public IEnumerable<FooBar> GetRecentItems()

или же

public IList<FooBar> GetRecentItems()

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

Это список & lt; T & gt; или IList & lt; T & gt; ты спрашиваешь? Название и вопрос говорят о разных вещах ... Fredrik Mörk
При любой возможности пользовательский интерфейс IEnumerable или Ilist вместо конкретного типа. Usman Masood
Я возвращаю коллекции в виде списка & lt; T & gt ;. Я не вижу необходимости возвращать IEnumberable & lt; T & gt; так как вы можете извлечь это из списка & lt; T & gt; Chuck Conway
возможный дубликатienumerablet-as-return-type nawfal
смотрите также:stackoverflow.com/questions/381208/ienumerablet-as-return-type Mauricio Scheffer

Ваш Ответ

13   ответов
0

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

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

Помните, что перемещение UP в коллекцию из IEnumerable в интерфейсе будет работать, переход в IEnumerable из коллекции приведет к поломке существующего кода.

Если все эти мнения кажутся противоречивыми, то это потому, что решение является субъективным.

0

как все уже сказали, это зависит, если вы не хотите добавлять / удалять функциональность на вызывающем слое, тогда я буду голосовать за IEnumerable, поскольку он обеспечивает только итерацию и базовую функциональность, которые в проектном представлении мне нравятся. Возвращая IList, мои голоса всегда повторяются, но это в основном то, что вам нравится, а что нет. с точки зрения производительности я думаю, что они больше одинаковы.

17

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

Будьте свободны в том, что вам требуется, и четко в том, что вы предоставляете.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
4

I think you can use either, but each has a use. Basically List is IEnumerable but you have count functionality, add element, remove element

IEnumerable is not efficient for counting elements

Если коллекция предназначена только для чтения, или изменение коллекции контролируетсяParent затем возвращаяIList Просто дляCount не очень хорошая идея

В Линке естьCount() метод расширения наIEnumerable<T> который внутри CLR будет ярлык для.Count если базовый тип имеетIList, поэтому разница в производительности незначительна.

Как правило, я считаю, что лучше возвращать IEnumerable там, где это возможно, если вам нужно сделать дополнения, а затем добавить эти методы в родительский класс, в противном случае потребитель управляет коллекцией в Model, что нарушает принципы, например,manufacturer.Models.Add(model) нарушает закон Деметры. Конечно, это всего лишь рекомендации, а не жесткие и быстрые правила, но пока у вас нет полного понимания применимости, лучше следовать слепо, чем вообще не следовать.

public interface IManufacturer 
{
     IEnumerable<Model> Models {get;}
     void AddModel(Model model);
}

(Примечание. При использовании nNHibernate может потребоваться сопоставить частный IList с использованием разных методов доступа.)

19

Это зависит от...

Возвращает наименее производный тип (IEnumerable) предоставит вам больше возможностей для изменения базовой реализации в будущем.

Возврат более производного типа (IList) предоставляет пользователям вашего API больше операций над результатом.

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededmsdn.microsoft.com/en-us/library/92t2ye13(v=vs.110).aspx)\
40

Это действительно зависит от того, почему вы используете этот конкретный интерфейс.

Например,IList<T> имеет несколько методов, которые не представлены вIEnumerable<T>:

  • IndexOf(T item)
  • Insert(int index, T item)
  • RemoveAt(int index)

и свойства:

  • T this[int index] { get; set; }

Если вам нужны эти методы каким-либо образом, то обязательно вернитеIList<T>.

Also, if the method that consumes your IEnumerable<T> result is expecting an IList<T>, it will save the CLR from considering any conversions required, thus optimizing the compiled code.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededmayError: User Rate Limit Exceeded
0

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

IEnumerable неэффективно для подсчета элементов или получения определенного элемента в коллекции.

List это коллекция, которая идеально подходит для поиска определенных элементов, простого добавления или удаления элементов.

Вообще пытаюсь использоватьList где это возможно, так как это дает мне больше гибкости.

Use List<FooBar> getRecentItems() rather than IList<FooBar> GetRecentItems()

0

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

Однако, если вам нужно количество элементов, не забывайте, что между IEnumerable и IList есть еще один слой -ICollection.

7

List<T> предлагает вызывающему коду множество других функций, таких как изменение возвращаемого объекта и доступ по индексу. Таким образом, вопрос сводится к следующему: в конкретном случае использования вашего приложения вы ХОТИТЕ поддерживать такие варианты использования (предположительно, возвращая только что созданную коллекцию!), Для удобства вызывающего абонента, или вам нужна скорость для простого случай, когда все, что нужно вызывающему, - это циклически проходить по коллекции, и вы можете безопасно вернуть ссылку на реальную базовую коллекцию, не опасаясь, что она будет ошибочно изменена, и т. д.?

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
8

Следует учитывать, что если вы используете оператор LINQ отложенного выполнения для генерации вашегоIEnumerable<T>звонит.ToList() перед возвратом из вашего метода означает, что ваши элементы могут повторяться дважды - один раз для создания списка, и один раз, когда вызывающий объект просматривает циклически, фильтрует или преобразовывает возвращаемое значение. Когда это целесообразно, мне нравится избегать преобразования результатов LINQ-to-Objects в конкретный список или словарь до тех пор, пока это не потребуется. Если моему вызывающему объекту нужен List, то это единственный простой вызов метода - мне не нужно принимать это решение за него, и это делает мой код немного более эффективным в тех случаях, когда вызывающий объект просто выполняет foreach.

Error: User Rate Limit Exceeded KingNestor
Error: User Rate Limit Exceeded
60

Руководства по проектированию рамок рекомендуют использовать классКоллекция когда вам нужно вернуть коллекцию, которая может быть изменена вызывающей стороной илиReadOnlyCollection Только для чтения.

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

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

Имейте в виду, что LINQ содержит несколько хитростей и оптимизирует определенные вызовы в зависимости от типа, над которым они выполняются. Так, например, если вы выполняете Count, а лежащая в основе коллекция - это List, она НЕ будет проходить через все элементы.

Лично для ORM я бы придерживалсяCollection<T> как мое возвращаемое значение.

Error: User Rate Limit ExceededGuidelines for CollectionsError: User Rate Limit Exceeded
1

Это не так просто, когда вы говорите о возвращаемых значениях вместо входных параметров. Когда это входной параметр, вы точно знаете, что вам нужно делать. Итак, если вам нужно иметь возможность перебирать коллекцию, вы берете IEnumberable, а если вам нужно добавить или удалить, вы берете IList.

В случае возвращаемого значения оно является более жестким. Что ожидает ваш абонент? Если вы вернете IEnumerable, он не узнает a priori, что он может сделать из него IList. Но если вы вернете IList, он будет знать, что он может перебирать его. Таким образом, вы должны принять во внимание, что ваш собеседник собирается делать с данными. Функциональность, в которой нуждается / ожидает ваш абонент, - это то, что должно определяться при принятии решения о том, что возвращать.

0

Я мог бы быть немного здесь, видя, что никто больше не предложил это до сих пор, но почему бы вам не вернуть(I)Collection<T>?

Из того, что я помню,Collection<T> был предпочтительным типом возврата болееList<T> потому что это абстрагирует от реализации. Все они реализуютIEnumerable, но это звучит для меня слишком низкоуровнево для работы.

Похожие вопросы