[.NET, Программирование] Принятого не воротай: Enumerable vs List
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Когда-то я работал в команде, где слегка недолюбливали LINQ, за то, что такой код якобы сложно отлаживать. У нас была договоренность: после каждой цепочки LINQ, разработчик создает локальную переменную, в которую записывает результат ToArray(). Независимо от того, потребуется ли массив далее по методу, или он работает только с IEnumerable. Перед return, результат также приводился к массиву, кажется, во всей кодовой базе не было методов, возвращающих или принимающих коллекцию, отличную от массива.Бородатое легаси! - подумаете вы и будете правы. Однако, несмотря то, что прошло много лет, с тех пор, как LINQ стал использоваться повсеместно, а IDE позволяют смотреть данные в отладке, некоторые разработчики все еще плохо представляют себе критерии выбора принимаемого и возвращаемого типа, если речь заходит о коллекциях.
Начнем с того, что есть коллекция? Поскольку BCL имеет одноименный тип данных, важно понимать, что коллекция - это тип данных, спроектированный для оперирования группой элементов, имеющих некую общую характеристику (тип данных). Таким образом, все, что можно перечислить является коллекцией.Предпочитайте абстракцииНезависимо от того, возвращаете вы или принимаете данные, удобнее работать с абстракциями. Вы контролируете доступ к объекту, предоставляя только необходимые члены. Вы также можете безболезненно поменять реализацию, не нарушая имеющийся код работы с параметром или возвращаемым значением. Возвращать конкретный тип имеет смысл, когда функционала стандартного интерфейса недостаточно, а выделять специфичный не имеет смысла.Lazy loadingВопрос - а прогрузились ли данные(например в IEnumerable) или нет, сам по себе не касается типа. Метод может возвращать как свою реализацию IList, так и стандартную, при этом с отложенной загрузкой данных. Информировать пользователя о том, используется ли lazy loading, посредством возвращаемого типа - плохая идея. Вы обременяете тип несвойственными ему обязанностями. Комментарий, либо специфичный постфикс 'Lazy' в названии метода, будут более удачным решением, если это не ясно из контекста.IRealonlyCollectionНесмотря на то, что по тем или иным причинам, у нас нет IArray, у нас есть IRealonlyCollection, добавляющий к перечислению свойство-размер.
namespace System.Collections.Generic
{
public interface IReadOnlyCollection : IEnumerable, IEnumerable
{
int Count { get; }
}
}
Соответствующий класс-враппер был добавлен в версии фреймворка 4.5, для удобного создания read-only коллекций. К нему легко можно преобразовать как Array, так и List, поскольку оба они реализуют IList. С IEnumerable дела обстоят хуже… Здесь, чтобы получить IRealonlyCollection, вам так или иначе придётся сначала получить List. Таким образом, де-факто стандартом здесь будет являться List. Возвращать Array или IRealonlyCollection вместо List, смысл есть только когда вам важно подчеркнуть неизменяемость. Во всех остальных случаях IList предложит более широкую функциональность примерно за ту же стоимость.Возвращайте пустые коллекции вместо nullКажется, уже все про это знают, тем не менее, я то и дело, иногда, то тут, то там, получаю null. Это побуждает меня и коллег добавлять проверки на null, что сводит к минимуму комфортную работу с пустыми коллекциями. Задумайтесь - null это не 0 элементов. Возвращая 1 раз null, вы навсегда обрекаете пользователя штамповать проверки на null, там, где они избыточны. Например:
if(myEnumerable != null)
{
foreach(var item in myEnumerable)
{
}
}
Хуже, но более лаконично:
foreach(var item in myEnumerable ?? Enumerable.Empty<T>())
{
}
IEnumerable/ICollection/IList Для начала, вкратце, что есть что: IEnumerable собственно, неизменяемая коллекция - перечисление, вам доступен только перечислительIReadOnlyCollection : IEnumerableнеизменяемая коллекция - перечисление, вам доступен перечислитель и размерICollection : IEnumerableколлекция c возможностью добавлять и удалять элемены, также доступен размер и признак изменяемости(IsReadOnly)IReadOnlyList : IReadOnlyCollectionнеизменяемая коллекция с порядком следования элементов, вам доступен индексаторIList : ICollectionколлекция с порядком следования элементов, c возможностью добавлять и удалять элемены по индексуПринимайте максимально обобщенный тип, нет смысла принимать больше данных, чем требуется методу для работы. Более того, передавать кучу неиспользуемых данных это антипаттерн. Принимая IEnumerable вы предоставляете возможность пользователю передать, в том числе и более конкретные типы - ICollection, IList… не пребегая к преобразованию.Возвращайте максимально конкретный тип, нет смысла прятать за обощенный интерфейс те данные, которыми вы уже располагаете, в результате работы метода. Если вы имеете массив то вы ничего не теряете, возвращая IRealonlyCollection. Возвращая IEnumerable вы скрываете знание о размере и в случае, если оно понадобится пользователю, прийдется изменять согнатуру метода, а если это невозможно - создавать дублирующий метод-перегрузку. Если результатом работы вашего метода является коллекция фиксированного размера и вы хотите избежать lazy loading, имеет смысл вернуть IList или ICollection, если вам важно указать пользователю на неизменяемость - их read-only аналоги.Web API и HTTPЕсли у вас одна часть приложения общается с другой частью по HTTP, например это разные слои сервисов или микросервисы, вы вероятно будете делать зарос из одного сервиса в другой через класс-клиент. И здесь, на секунду может показаться, что у вас есть выбор использовать что угодно, начиная с IEnumerable и заканчивая IList. На самом деле, по HTTP ваша коллекция уедет как JSON - серрилизованый массив, вся целиком. И приедет, если мы говорим о популярных дессерилизаторах(Newtonsoft.Json, System.Text.Json), не иначе как List. В данном случае нет никакого смысла отдавать\принимать что-то другое. Указывая IEnumerable в response контроллера вы только усложняете понимание кода.Я не касался темы производительности, поскольку, если ставить её во главу угла, критерии выбора будут сильно зависеть от конкретной ситуации, а это уже совсем другая история.Буду рад поправкам и дополнениям, рекомендую ознакомиться с Framework Design Guidelines for Collections.
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Разработка под Android, Разработка мобильных приложений] 20 инструментов Android-разработчика, о которых вы могли не знать (перевод)
- [Программирование] Что значит быть программистом?
- [Программирование, Проектирование и рефакторинг, Go] Дневник изучения Go: запись 1
- [JavaScript, Программирование, Разработка веб-сайтов] 200 теоретических вопросов по JavaScript
- [.NET, C#] Немного о велосипедах
- [Программирование, Учебный процесс в IT, Карьера в IT-индустрии, Конференции] Бесплатные онлайн-мероприятия по разработке (15 сентября – 23 сентября)
- [Визуализация данных, Программирование микроконтроллеров, Разработка для интернета вещей, Умный дом, Интернет вещей] SCADA «BortX» с поддержкой языка управления в рамках ANSI /ISA-88 для ESP8266
- [Программирование микроконтроллеров] Продолжение очередной статьи: STM32 для начинающих. Интерфейсы
- [Программирование микроконтроллеров] Очередная статья: STM32 для начинающих
- [C++, Анализ и проектирование систем, ООП, Программирование, Программирование микроконтроллеров] Micro Property — минималистичный сериализатор двоичных данных для embedded систем
Теги для поиска: #_.net, #_programmirovanie (Программирование), #_c#, #_ienumerable, #_ilist, #_.net, #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:14
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Когда-то я работал в команде, где слегка недолюбливали LINQ, за то, что такой код якобы сложно отлаживать. У нас была договоренность: после каждой цепочки LINQ, разработчик создает локальную переменную, в которую записывает результат ToArray(). Независимо от того, потребуется ли массив далее по методу, или он работает только с IEnumerable. Перед return, результат также приводился к массиву, кажется, во всей кодовой базе не было методов, возвращающих или принимающих коллекцию, отличную от массива.Бородатое легаси! - подумаете вы и будете правы. Однако, несмотря то, что прошло много лет, с тех пор, как LINQ стал использоваться повсеместно, а IDE позволяют смотреть данные в отладке, некоторые разработчики все еще плохо представляют себе критерии выбора принимаемого и возвращаемого типа, если речь заходит о коллекциях. Начнем с того, что есть коллекция? Поскольку BCL имеет одноименный тип данных, важно понимать, что коллекция - это тип данных, спроектированный для оперирования группой элементов, имеющих некую общую характеристику (тип данных). Таким образом, все, что можно перечислить является коллекцией.Предпочитайте абстракцииНезависимо от того, возвращаете вы или принимаете данные, удобнее работать с абстракциями. Вы контролируете доступ к объекту, предоставляя только необходимые члены. Вы также можете безболезненно поменять реализацию, не нарушая имеющийся код работы с параметром или возвращаемым значением. Возвращать конкретный тип имеет смысл, когда функционала стандартного интерфейса недостаточно, а выделять специфичный не имеет смысла.Lazy loadingВопрос - а прогрузились ли данные(например в IEnumerable) или нет, сам по себе не касается типа. Метод может возвращать как свою реализацию IList, так и стандартную, при этом с отложенной загрузкой данных. Информировать пользователя о том, используется ли lazy loading, посредством возвращаемого типа - плохая идея. Вы обременяете тип несвойственными ему обязанностями. Комментарий, либо специфичный постфикс 'Lazy' в названии метода, будут более удачным решением, если это не ясно из контекста.IRealonlyCollectionНесмотря на то, что по тем или иным причинам, у нас нет IArray, у нас есть IRealonlyCollection, добавляющий к перечислению свойство-размер. namespace System.Collections.Generic
{ public interface IReadOnlyCollection : IEnumerable, IEnumerable { int Count { get; } } } if(myEnumerable != null)
{ foreach(var item in myEnumerable) { } } foreach(var item in myEnumerable ?? Enumerable.Empty<T>())
{ } =========== Источник: habr.com =========== Похожие новости:
Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:14
Часовой пояс: UTC + 5