День восемьдесят седьмой. #ЗаметкиНаПолях
Выражение yield return. Начало
Выражение
Небольшой пример, не имеющий особого смысла, но полезный для отладки и понимания работы
Yield return против обычных циклов
Вот другой пример. Здесь обычный цикл, возвращающий список:
Выполнение этого кода по шагам:
1. Вызывается
2. Выполняется весь метод и создаётся список.
3. Цикл
4. В результате числа от 1 до 5 выводятся в консоль.
Аналогичный метод с помощью
1. Вызывается
2. Тип возвращаемого значения этого метода
3. В каждой итерации цикла
4. В результате в консоли выводятся числа от 1 до 5.
Источники:
- https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/yield
- https://www.kenneth-truyers.net/2016/05/12/yield-return-in-c/
Продолжение следует…
Выражение yield return. Начало
Выражение
yield return
, вероятно, одна из наименее известных функций в C#. Несмотря на то, что большинство разработчиков о нём слышали, это выражение часто понимается неправильно. Использование ключевого слова yield
в методе означает, что этот метод, оператор или акцессор get
является итератором. Использование yield
исключает необходимость применения явного дополнительного класса для хранения перечисления. Примеры использования:yield return <expression>; // возвращает каждый элемент по одномуМетод-итератор используется путем применения оператора
yield break; // завершает итерацию
foreach
или запроса LINQ. Каждая итерация цикла foreach
вызывает метод-итератор. При достижении в методе-итераторе оператора yield return
возвращается <expression>
и сохраняется текущее расположение в коде. При следующем вызове метода-итератора выполнение возобновляется с этого места.Небольшой пример, не имеющий особого смысла, но полезный для отладки и понимания работы
yield return
:IEnumerable GetNumbers() {Вызовем его:
yield return 1;
yield return 2;
yield return 3;
}
foreach(var number in GetNumbers())Когда вы пройдёте его по шагам в отладке, вы увидите, что текущая строка выполнения прыгает между циклом
Console.WriteLine(number);
foreach
и выражениями yield return
. То есть каждая итерация цикла вызывает метод-итератор GetNumbers
до очередного выражения yield return
. Значение возвращается вызывающему коду, а позиция в методе-итераторе сохраняется. Выполнение возобновляется с этой позиции при следующем вызове метода-итератора. Это продолжается, пока не будут вызваны все выражения yield return
, либо не встретится yield break
.Yield return против обычных циклов
Вот другой пример. Здесь обычный цикл, возвращающий список:
IEnumerable<int> GenerateWithoutYield();
{
var i = 0;
var list = new List<int>();
while (i<5)
list.Add(++i);
return list;
}
foreach(var number in GenerateWithoutYield())
Console.WriteLine(number)
Выполнение этого кода по шагам:
1. Вызывается
GenerateWithoutYield
.2. Выполняется весь метод и создаётся список.
3. Цикл
foreach
проходит по всем значениям списка.4. В результате числа от 1 до 5 выводятся в консоль.
Аналогичный метод с помощью
yield return
:IEnumerable<int> GenerateWithYield()На первый взгляд этот метод тоже возвращает список из 5 чисел. Но из-за выражения
{
var i = 0;
while (i<5)
yield return ++i;
}
foreach(var number in GenerateWithYield())
Console.WriteLine(number);
yield
код выполняется совершенно по-другому. Метод вообще не возвращает списка. Он создаёт итератор с обещанием вернуть 5 чисел. Несмотря на то, что результат тот же, есть некоторые нюансы выполнения:1. Вызывается
GenerateWithYield
.2. Тип возвращаемого значения этого метода
IEnumerable
, но это не список, а обещание вернуть последовательность чисел при запросе. Точнее создаётся итератор, позволяющий выполнить это обещание.3. В каждой итерации цикла
foreach
вызывается метод-итератор. При достижении выражения yield return
возвращается значение, а текущее положение запоминается. Выполнение продолжается с этого места при следующем вызове метода-итератора.4. В результате в консоли выводятся числа от 1 до 5.
Источники:
- https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/yield
- https://www.kenneth-truyers.net/2016/05/12/yield-return-in-c/
Продолжение следует…