Возможный дубликат:
С# - Правильное использование возврата доходности
Что может быть реальным вариантом использования С#?
Спасибо.
Возможный дубликат:
С# - Правильное использование возврата доходности
Что может быть реальным вариантом использования С#?
Спасибо.
Если вы хотите отложенное выполнение.
Это имеет смысл в большинстве случаев, когда альтернативой является создание временной коллекции.
Рассмотрим этот сценарий: у меня есть список целых чисел, и я хочу перечислить их квадраты.
Я мог бы сделать это:
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<int>
для этой цели. Я мог бы использовать 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<int>
перед возвратом, вышеуказанный код будет делать гораздо больше работы, чем необходимо.
На странице 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
эффективно "приостанавливается" после каждой итерации, чтобы позволить вызывающей процедуре выполнять какое-либо действие. В этом случае распечатайте результат.
Когда вам слишком лениво написать свой собственный IEnumerator;)
См. в этой статье.
Выход действует как возвращаемый-placeholder - это нелокальная точка возврата goto, которая сохраняет среду метода и позволяет коду "прыгать" обратно. Подобным образом (тип инвертированного) передается делегат в метод, который позволяет вам вводить определенную логику в рамках другого метода, закрытие позволяет вам выполнять различные типы работы "вокруг" более общего метода, позволяя сохранить код небольшим, модульным и повторно используемым.
Это может сделать гораздо более эффективный код. Вместо создания экземпляра очень большой коллекции можно было бы позволить отдельным объектам действовать последовательно (и они отбрасываются после каждой операции). Я предполагаю, что вы могли бы построить случаи, когда простой итератор было бы чрезвычайно сложно построить.