Как стать автором
Обновить

Реализация итераторов в C# (часть 2)

Время на прочтение2 мин
Количество просмотров11K
Автор оригинала: Raymond Chen
Реализация итераторов в C# (часть 1).

Теперь, когда вы имеете в своём багаже общее представление о том, что стоит за итераторами, вы уже можете ответить на некоторые вопросы их использования. Вот сценарий, основанный на реальных событиях:

У меня есть большой и сложный итератор, и я хочу отрефакторить его. Для большей наглядности условимся, что перечислитель считает от 1 до 100 дважды. (Разумеется, в реальной жизни итератор не будет столь простым.)
IEnumerable<int> CountTo100Twice()
{
    int i;
    for (i = 1; i <= 100; i++) {
        yield return i;
    }
    for (i = 1; i <= 100; i++) {
        yield return i;
    }
}

Как мы знаем из Pragramming 101, мы можем вынести общий код в подпрограмму и вызвать её. Но когда я так делаю, я получаю ошибку компилятора:
IEnumerable<int> CountTo100Twice()
{
    CountTo100();
    CountTo100();
}
 
void CountTo100()
{
    int i;
    for (i = 1; i <= 100; i++) {
        yield return i;
    }
}

Что я делаю не так? Как мне перенести “подсчёт до 100” в подпрограмму и дважды вызвать её из функции CountTo100Twice?

Как мы только что увидели, итераторы это вовсе не подпрограммы. Представленная выше техника прекрасно работала бы, если бы мы строили итераторы из, скажем, волокон вместо конечных автоматов. Но раз уж используются автоматы, yield return выражения должны располагаться на “верхнем уровне”. Так как вы будете итерировать с помощью подпрограмм?

Вы делаете саму подпрограмму итератором, а затем “вытягиваете” результаты из главной функции:
IEnumerable<int> CountTo100Twice()
{
    foreach (int i in CountTo100()) yield return i;
    foreach (int i in CountTo100()) yield return i;
}
 
IEnumerable<int> CountTo100()
{
    for (i = 1; i <= 100; i++) {
        yield return i;
    }
}

Упражнение: Рассмотрим следующий фрагмент:
foreach (int i in CountTo100Twice()) {
    // ...
}

Объясните, что произойдёт на 150-ом (стопятидесятом) вызове MoveNext() в цикле выше. Обдумайте последствие этого для рекурсивных алгоритмов (таких как обход деревьев).
Теги:
Хабы:
Всего голосов 22: ↑17 и ↓5+12
Комментарии3

Публикации

Истории

Работа

.NET разработчик
76 вакансий

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань