2009-02-20 3 views
3

Обычно мои методы являются следующие:Лучшая практика, когда возвращая массив значений (.NET)

public List<int> Method1(int input) 
{ 
    var output = new List<int>(); 
    //add some items to output 
    return output; 
} 

Но FxCop советует другой IList реализации вместо списка, но я не могу вспомнить, какой. Альтернативы включают возвращение его в качестве IList, ICollection или IEnumerable для большей гибкости или совершенно иным образом, как код ниже .:

public int[] Method2(int input) 
{ 
    var output = new List<int>(); 
    //add some items to output 
    return output.ToArray(); 
} 

Из всех альтернатив, все при условии, и все возможности, которая считается лучшей практикой?

ответ

5

«Рекомендации по проектированию рамочные» (2-е изд) в §8.3.1 имеет достаточно много, чтобы сказать о коллекциях как возвращаемые значения, суммарные:

  • НЕ обеспечивают настраиваемые свойства коллекции.
  • DOCollection<T> или подкласс Collection<T> для свойств или возвращаемых значений, представляющих коллекции чтения/записи.
  • DO использование ReadOnlyCollection<T>, подкласс ReadOnlyCollection<T>, или в редких случаях IEnumerable<T> для свойств или возвращаемых значений, представляющих для чтения только коллекции.

(и многое другое, но эти три захвата ядро).

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

Я хотел бы вернуть IList<T> и гарантировать, что я не определяю фактический тип, который я возвращаю, если только я не возвращал итератор (когда я буду использовать IEnumerable<T>).

6

IEnumerable/IEnumerable < T>, если вы специально не нужен список, то вы должны вернуться IList < T>

+0

Согласен, но можете ли вы расшифровать почему? – mmcdole

+0

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

+0

Например, возможно, прямо сейчас вы возвращаете массив, но в какой-то момент в будущем вы обновите код, чтобы вместо этого вернуть список . Если вы обещали, что вы возвращаете IEnumerable , код вызова будет работать нормально. –

2

Верните интерфейс, что вам нужно в коде вызова этого метода.

Если вам нужно сделать список действий по результату, верните IList<T>. Если вам просто нужно перечислить результаты, верните IEnumerable<T>.

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

3

ReadOnlyCollection<T> - другой вариант.

+0

Но только если вы не хотите, чтобы у вызывающего появилась возможность обновить список. В любом случае +1 к вашему ответу. –

1

Это зависит.

Вы хотите, чтобы вызывающий абонент мог изменять элементы и видеть эти изменения? Массивы могут быть изменены. Интерфейс IList определяет методы модификации (но реализация может не позволить это).

Можете ли вы уточнить предупреждение FxCop?

Kent

+0

FxCop рекомендует вам возвращать ReadOnlyCollection вместо списка –

+0

Это похоже. , , странный. Как я уже сказал, что, если вы действительно хотите, чтобы абоненты могли изменять содержимое? –

+0

«Не подвергайте список в объектной модели. Используйте Коллекция , ReadOnlyCollection или KeyedCollection вместо. Список предназначен для использования от реализации, а не в объектной модели API. Список оптимизирован для производительности за счет длинных –

1

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

1

Я почти всегда иду с List, потому что он дает мне методы, которые я часто нахожу наиболее полезными.

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

+0

Список удобен для pre-LINQ для таких вещей, как «Найти», но post-3.5 не дает вам ничего, что вы не можете получить из стандартных методов расширения IEnumerable. –

5

Эрик Липперт имеет хорошее сообщение о том, почему returning an array is usually a bad idea.

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

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

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

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

Смежные вопросы