Каковы реальные результаты использования урожая?

Я знаю, что делает yield, и я видел несколько примеров, но я не могу думать о реальных приложениях, вы использовали его для решения какой-то конкретной проблемы?

(Идеально какая-то проблема, которая не может быть решена каким-либо другим способом)

Ответ 1

Я понимаю, что это старый вопрос (до Джон Скит?), но я сам рассматривал этот вопрос в последнее время. К сожалению, текущие ответы здесь (на мой взгляд) не упоминают наиболее очевидное преимущество отчета о выходе.

Самое большое преимущество оператора yield заключается в том, что он позволяет выполнять итерацию по очень большим спискам с гораздо более эффективным использованием памяти, а затем использовать стандартный список.

Например, скажем, у вас есть запрос к базе данных, который возвращает 1 миллион строк. Вы можете извлекать все строки с помощью DataReader и хранить их в списке, поэтому для этого необходимо указать list_size * row_size байты памяти.

Или вы можете использовать оператор yield для создания Iterator и только когда-либо хранить одну строку в памяти за раз. Фактически это дает вам возможность обеспечить "потоковое" использование по большим наборам данных.

Кроме того, в коде, использующем Iterator, вы используете простой цикл foreach и можете решить выйти из цикла по мере необходимости. Если вы рано сломаетесь, вы не заставили восстановить весь набор данных, когда вам нужны только первые 5 строк (например).

Относительно:

Ideally some problem that cannot be solved some other way

Оператор yield не дает вам ничего, что вы не могли бы сделать, используя свою собственную реализацию итератора, но это избавляет вас от необходимости писать часто сложный код. Есть очень мало проблем (если они есть), которые не могут решить более одного пути.

Вот несколько более свежих вопросов и ответов, которые дают более подробную информацию:

Добавлена ​​добавленная стоимость ключевого слова?

Является ли доход полезным вне LINQ?

Ответ 2

на самом деле я использую его не традиционным способом на моем сайте IdeaPipe

public override IEnumerator<T> GetEnumerator()
{
    // goes through the collection and only returns the ones that are visible for the current user
    // this is done at this level instead of the display level so that ideas do not bleed through
    // on services
    foreach (T idea in InternalCollection)
        if (idea.IsViewingAuthorized)
            yield return idea;
}

поэтому в основном он проверяет, разрешен ли просмотр идеи в настоящее время, и если она возвращает идею. Если это не так, это просто пропущено. Это позволяет мне кэшировать идеи, но все же отображать идеи для пользователей, которые авторизованы. Else, я должен был бы каждый раз вытаскивать их на основании разрешений, когда они только пересматриваются каждые 1 час.

Ответ 3

Одно интересное использование - это механизм асинхронного программирования esp для задач, выполняющих несколько этапов, и для каждого шага требуется один и тот же набор данных. Двумя примерами этого может быть Jeffery Richters AysncEnumerator Часть 1 и Часть 2. Concurrency и время согласования (CCR) также используют этот метод Итераторы CCR.

Ответ 4

Операторы LINQ в классе Enumerable реализуются как итераторы, созданные с помощью оператора yield. Он позволяет вам цепочки операций, таких как Select() и Where(), без фактического перечисления чего-либо, пока вы фактически не используете перечислитель в цикле, как правило, используя оператор foreach. Кроме того, поскольку только одно значение вычисляется при вызове IEnumerator.MoveNext(), если вы решили остановить среднюю коллекцию, вы сможете сэкономить удар производительности при вычислении всех результатов.

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

Ответ 5

Другим полезным преимуществом для выхода является выполнение функции на элементах IEnumerable и возвращение результата другого типа, например:

public delegate T SomeDelegate(K obj);

public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action)
{
    foreach (var i in list)
        yield return action(i);
}

Ответ 6

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

Ответ 7

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

void Main()
{
    var StartDate = DateTime.Parse("01/01/2013");
    var EndDate = DateTime.Parse("06/30/2013");
    foreach (var d in GetPayrollDates(StartDate, EndDate)) {
        Console.WriteLine(d);
    }
}

// Calculate payroll dates in the given range.
// Assumes the first date given is a payroll date.
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int     daysInPeriod = 14) {
    var thisDate = startDate;
    while (thisDate < endDate) {
        yield return thisDate;
        thisDate = thisDate.AddDays(daysInPeriod);
    }
}