Русский
Русский
English
Статистика
Реклама

Ilist

Принятого не воротай Enumerable vs List

15.09.2020 08:18:15 | Автор: admin

Когда-то я работал в команде, где слегка недолюбливалиLINQ, за то, что такой код якобы сложно отлаживать. У нас была договоренность: после каждой цепочкиLINQ, разработчик создает локальную переменную, в которую записывает результатToArray(). Независимо от того, потребуется ли массив далее по методу, или он работает только сIEnumerable. Передreturn, результат также приводился к массиву,кажется,во всей кодовой базе не было методов, возвращающих или принимающихколлекцию,отличную от массива.

Бородатоелегаси! - подумаете вы и будете правы. Однако, несмотря то, что прошло много лет, с тех пор, как LINQстал использоваться повсеместно, аIDEпозволяют смотреть данные в отладке, некоторые разработчики все еще плохо представляют себе критерии выбора принимаемого и возвращаемого типа, если речь заходит о коллекциях.

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

Предпочитайте абстракции

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

Lazy loading

Вопрос - а прогрузились ли данные(например вIEnumerable)или нет, сам по себе не касается типа. Метод может возвращать как свою реализациюIList, так и стандартную, при этом с отложенной загрузкой данных.Информироватьпользователя о том, используется лиlazyloading, посредством возвращаемого типа - плохая идея. Вы обременяете тип несвойственными ему обязанностями. Комментарий, либо специфичный постфикс '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.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru