Когда 'Урожай' действительно необходим? [дубликат]

11
задан Community 23 May 2017 в 10:29
поделиться

4 ответа

Когда вам нужно отложенное выполнение.

Это имеет смысл в большинстве случаев, когда альтернативой является создание временной коллекции.

Рассмотрим такой сценарий: у меня есть список целых чисел, и я хочу перечислить их квадраты.

Я мог бы сделать вот что:

public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
    List<int> squares = new List<int>();
    foreach (int number in numbers)
        squares.Add(number * number);

    return squares;
}

Затем я мог бы суммировать квадраты, взять их среднее значение, найти наибольшее и т.д.

Но мне действительно не нужно было заполнять новый List для этой цели. Я мог бы использовать yield для перебора исходного списка и возврата квадратов по одному:

public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
    foreach (int number in numbers)
        yield return number * number;
}

Тот факт, что это действительно имеет значение, может быть неочевидным, пока вы не начнете работать с очень большими коллекциями, где заполнение временных коллекций оказывается весьма расточительным.

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

IEnumerable<int> numbers = GetLotsOfNumbers();
var squares = numbers.Squares();
int firstBigSquare = squares
    .Where(x => x >= 1000)
    .FirstOrDefault();

Но если бы мой метод Squares перед возвратом заполнял весь List, то приведенный выше код выполнял бы потенциально гораздо больше работы, чем нужно.

25
ответ дан 3 December 2019 в 01:13
поделиться

Когда вам лень писать свой собственный IEnumerator ;)

8
ответ дан 3 December 2019 в 01:13
поделиться

Со страницы MSDN о yield:

Используется в блоке итератора для предоставления значения объекту перечислителя или для сигнализации окончания итерации.

Вы используете его при создании пользовательского итератора. Используя пример со страницы:

// yield-example.cs
using System;
using System.Collections;
public class List
{
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}

yield означает, что цикл while внутри Power фактически "приостанавливается" после каждой итерации, чтобы дать возможность вызывающей программе выполнить какое-то действие. В данном случае распечатать результат.

10
ответ дан 3 December 2019 в 01:13
поделиться

См. в этой статье .

Yield действует как заполнитель возврата - это нелокальная точка возврата goto, которая сохраняет среду метода и позволяет коду «возвращаться» обратно. Подобным образом (в инвертированном виде) передача делегата в метод, который позволяет вам внедрять определенную логику в другой метод, замыкания позволяют выполнять различные типы работы «вокруг» более общего метода, позволяя сохранить небольшой размер кода, модульность и возможность повторного использования.

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

1
ответ дан 3 December 2019 в 01:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: