После почти 4 лет опыта я не видел кода, в котором используется ключевое слово yield . Может ли кто-нибудь показать мне практическое использование (наряду с объяснением) этого ключевого слова, и если да, то нет ли других способов, чтобы легче было выполнить то, что оно может сделать?
76
yield
вообще можно использовать.Ответы:
КПД
yield
Ключевое слово эффективно создает ленивое перечисление по пунктам сбора , которые могут быть гораздо более эффективным. Например, если вашforeach
цикл повторяет только первые 5 элементов по 1 миллиону элементов, то это всеyield
возвращается, и вы сначала не создали внутреннюю коллекцию из 1 миллиона элементов. Точно так же вы хотите использоватьyield
сIEnumerable<T>
возвращаемыми значениями в ваших собственных сценариях программирования для достижения той же эффективности.Пример эффективности, полученной по определенному сценарию
Не метод итератора, потенциальное неэффективное использование большой коллекции
(промежуточная коллекция построена с большим количеством элементов)
Версия итератора, эффективная
(промежуточная коллекция не создается)
Упростить некоторые сценарии программирования
В другом случае это облегчает программирование некоторых видов сортировки и объединения списков, поскольку вы просто
yield
возвращаете элементы в нужном порядке, а не сортируете их в промежуточную коллекцию и меняете их там. Есть много таких сценариев.Одним из примеров является объединение двух списков:
Этот метод возвращает один непрерывный список элементов, фактически объединение без промежуточной коллекции.
Больше информации
yield
Ключевое слово может быть использовано только в контексте метода итератора (имеющий тип возвратаIEnumerable
,IEnumerator
,IEnumerable<T>
, илиIEnumerator<T>
.) , И есть особые отношения сforeach
. Итераторы - это специальные методы. Выход документации MSDN и итератор документация содержит много интересной информации и объяснения понятий. Убедитесь , соотнести его с поforeach
ключевому слову , прочитав об этом тоже, чтобы дополнить ваше понимание итераторы.Чтобы узнать, как итераторы достигают своей эффективности, секрет заключается в IL-коде, сгенерированном компилятором C #. IL, сгенерированный для метода итератора, кардинально отличается от того, который генерируется для обычного (не итераторного) метода. В этой статье («Что в действительности генерирует ключевое слово доходность?») Дается такое понимание.
источник
database.Customers.Count()
перечисляет ли все перечисление клиентов, что требует более эффективного кода для прохождения каждого элемента?Некоторое время назад у меня был практический пример, давайте предположим, что у вас есть такая ситуация:
Объект кнопки не знает свою собственную позицию в коллекции. Такое же ограничение применяется для
Dictionary<T>
других типов коллекций.Вот мое решение с использованием
yield
ключевого слова:И вот как я это использую:
Мне не нужно делать
for
цикл по моей коллекции, чтобы найти индекс. Моя кнопка имеет идентификатор, и он также используется в качестве индекса вIndexerList<T>
, так что вы избегаете любых избыточных идентификаторов или индексов - это то, что мне нравится! Индекс / Id может быть произвольным числом.источник
Практический пример можно найти здесь:
http://www.ytechie.com/2009/02/using-c-yield-for-readability-and-performance.html
Существует несколько преимуществ использования yield по сравнению со стандартным кодом:
Однако, как сказал Jan_V (просто побейте меня этим на несколько секунд :-), вы можете обойтись без него, потому что внутренне компилятор будет генерировать код, практически идентичный в обоих случаях.
источник
Вот пример:
https://bitbucket.org/ant512/workingweek/src/a745d02ba16f/source/WorkingWeek/Week.cs#cl-158
Класс выполняет вычисления даты на основе рабочей недели. Я могу рассказать ученикам, что Боб работает с 9:30 до 17:30 каждый будний день с часовым перерывом на обед в 12:30. Обладая этими знаниями, функция AscendingShifts () будет выдавать рабочие объекты сдвига между указанными датами. Чтобы перечислить все рабочие смены Боба в период с 1 января по 1 февраля этого года, вы должны использовать его следующим образом:
Класс на самом деле не перебирает коллекцию. Тем не менее, сдвиги между двумя датами можно рассматривать как коллекцию.
yield
Оператор позволяет перебрать эту воображаемую коллекцию без создания самой коллекции.источник
У меня есть небольшой уровень данных БД, в котором есть
command
класс, в котором вы устанавливаете текст команды SQL, тип команды и возвращаете IEnumerable из «параметров команды».По сути, идея состоит в том, чтобы набирать команды CLR вместо того, чтобы вручную заполнять
SqlCommand
свойства и параметры все время.Итак, есть функция, которая выглядит так:
Класс, который наследует этот
command
класс, имеет свойстваAge
иName
.Затем вы можете создать новый
command
объект, заполненный его свойствами, и передать егоdb
интерфейсу, который фактически выполняет командный вызов.В общем, с командами SQL очень легко работать и сохранять их типизированными.
источник
Хотя случай слияния уже был рассмотрен в принятом ответе, позвольте мне показать вам метод расширения параметров yield-merge params ™:
Я использую это для создания пакетов сетевого протокола:
MarkChecksum
Метод, например, выглядит следующим образом . И этоyield
тоже имеет:Но будьте осторожны при использовании агрегатных методов, таких как Sum (), в методе перечисления, поскольку они запускают отдельный процесс перечисления.
источник
В репозитории Elastic Search .NET есть отличный пример использования
yield return
для разделения коллекции на несколько коллекций с указанным размером:https://github.com/elastic/elasticsearch-net-example/blob/master/src/NuSearch.Domain/Extensions/PartitionExtension.cs
источник
Разбираясь с ответом Jan_V, я попал в реальный случай, связанный с ним:
Мне нужно было использовать Kernel32 версии FindFirstFile / FindNextFile. Вы получаете ручку от первого звонка и подаете его на все последующие звонки. Оберните это в перечислитель, и вы получите то, что можете напрямую использовать с foreach.
источник