Вернуть интерфейс или класс

9

Предположим, у меня есть метод

public List<User> GetBatchOfUsers(IEnumerable<int> userIDs)
{
    List<User> users = new List<User>();

    // some database stuff

    return users;
}

Я прочитал, что было бы лучше вернуть интерфейс (либо IListили IEnumerable), а не возвращать List. Некоторые аргументы, которые я слышал для этого, заключаются в том, что он скрывает данные и дает разработчику API возможность изменить внутреннее представление данных на более позднем этапе.

Моя проблема с возвратом IEnumerable- это потеря функциональности, такой как произвольный доступ и Countсобственность.

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

Какова наилучшая практика для типа возврата?

Мэтью
источник
5
Гораздо важнее: взять интерфейс в качестве типа параметра.
Майкл Боргвардт

Ответы:

10

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

Что ж, если вы вернете интерфейс, вы сохраните большую гибкость. Вы можете изменить реализацию позже, чтобы получить другой конкретный тип. С другой стороны, это, очевидно, дает вызывающим абонентам меньше информации, поэтому они могут не иметь возможности выполнять определенные операции. (Например: если вы вернетесь List<T>, вызывающая сторона может использовать ConvertAll и т. Д., Чего они не смогут, если вы только объявите, что возвращаете IList<T>.) В некоторых ситуациях стоит указать конкретный тип.

Что касается метода Count или Sort, для этого нет стандартных интерфейсов сбора. Однако вы можете написать метод расширения для сортировки или подсчета любого IList.

Юсубы
источник
Думаю, это не очень сложное правило?
Матфея
да, это действительно зависит от использования.
Юсубов
1

Если вам нужна ваша коллекция, Countвы можете использовать ее ICollection<T>, что является достаточно общим.

dpiatkowski
источник
-1. Граф уже обсуждался, и этот ответ не добавляет ничего нового
superM
@ Конрад Рудольф, это не ответ, это комментарий.
СуперМ
@superM Я думаю, что это достаточно ценно, чтобы заслужить свой ответ, поскольку в нем явно указывается причина, по которой OP решает отказаться от интерфейсов.
Конрад Рудольф
1

Вы возвращаете то, что разумно для метода, который вы определяете. Что вы делаете, возвращая серию элементов (основное внимание уделяется элементам), или это возвращает коллекцию элементов (основное внимание уделяется коллекции в целом)? Стоит ли допускать отклонения в реализации коллекции? Если никогда не будет смысла использовать генератор или HashSetпросто использовать List.

Telastyn
источник
1

Специфично для примера метода: вы правы, возвращение IEnmuerable<T>означало бы, что вы потеряете функциональность Countи индексацию (хотя вы можете использовать методы LINQ Count()и ElementAt(), которые реализуются эффективно, если тип, который они используют на самом деле, реализует IList<T>).

Если вы вернетесь IList<T>, вы потеряете некоторую функциональность, но выигрыш в общем, вероятно, того стоит.

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

В .Net 4.5, есть такой интерфейс: IReadOnlyList<T>.

svick
источник
IReadOnlyListзвучит хорошо, когда я могу получить VS2013, спасибо!
Мэтью