КПД
yield
Ключевое слово эффективно создает ленивое перечисление по пунктам сбора , которые могут быть гораздо более эффективным. Например, если ваш foreach
цикл повторяет только первые 5 элементов по 1 миллиону элементов, то это все yield
возвращается, и вы сначала не создали внутреннюю коллекцию из 1 миллиона элементов. Точно так же вы хотите использовать yield
с IEnumerable<T>
возвращаемыми значениями в ваших собственных сценариях программирования для достижения той же эффективности.
Пример эффективности, полученной по определенному сценарию
Не метод итератора, потенциальное неэффективное использование большой коллекции
(промежуточная коллекция построена с большим количеством элементов)
// Method returns all million items before anything can loop over them.
List<object> GetAllItems() {
List<object> millionCustomers;
database.LoadMillionCustomerRecords(millionCustomers);
return millionCustomers;
}
// MAIN example ---------------------
// Caller code sample:
int num = 0;
foreach(var itm in GetAllItems()) {
num++;
if (num == 5)
break;
}
// Note: One million items returned, but only 5 used.
Версия итератора, эффективная
(промежуточная коллекция не создается)
// Yields items one at a time as the caller's foreach loop requests them
IEnumerable<object> IterateOverItems() {
for (int i; i < database.Customers.Count(); ++i)
yield return database.Customers[i];
}
// MAIN example ---------------------
// Caller code sample:
int num = 0;
foreach(var itm in IterateOverItems()) {
num++;
if (num == 5)
break;
}
// Note: Only 5 items were yielded and used out of the million.
Упростить некоторые сценарии программирования
В другом случае это облегчает программирование некоторых видов сортировки и объединения списков, поскольку вы просто yield
возвращаете элементы в нужном порядке, а не сортируете их в промежуточную коллекцию и меняете их там. Есть много таких сценариев.
Одним из примеров является объединение двух списков:
IEnumerable<object> EfficientMerge(List<object> list1, List<object> list2) {
foreach(var o in list1)
yield return o;
foreach(var o in list2)
yield return o;
}
Этот метод возвращает один непрерывный список элементов, фактически объединение без промежуточной коллекции.
Больше информации
yield
Ключевое слово может быть использовано только в контексте метода итератора (имеющий тип возврата IEnumerable
, IEnumerator
, IEnumerable<T>
, или IEnumerator<T>
.) , И есть особые отношения с foreach
. Итераторы - это специальные методы. Выход документации MSDN и итератор документация содержит много интересной информации и объяснения понятий. Убедитесь , соотнести его с по foreach
ключевому слову , прочитав об этом тоже, чтобы дополнить ваше понимание итераторы.
Чтобы узнать, как итераторы достигают своей эффективности, секрет заключается в IL-коде, сгенерированном компилятором C #. IL, сгенерированный для метода итератора, кардинально отличается от того, который генерируется для обычного (не итераторного) метода. В этой статье («Что в действительности генерирует ключевое слово доходность?») Дается такое понимание.