yield (справочник по C#)
Использование в операторе ключевого слова yield означает, что метод, оператор или метод доступа get, в котором присутствует это ключевое слово, является итератором. Использование yield для определения итератора исключает необходимость применения явного дополнительного класса (в котором содержится состояние перечисления; в качестве примера см. IEnumerator) при реализации шаблонов IEnumerable и IEnumerator для пользовательского типа коллекции.
В следующем примере показаны две формы оператора yield.
yield return <expression>;
yield break;
Заметки
Оператор yield return используется для возврата каждого элемента по одному.
Метод итератора используется путем применения оператора foreach или запроса LINQ. Каждая итерация цикла foreach вызывает метод итератора. При достижении в методе итератора оператора yield return возвращается expression и сохраняется текущее расположение в коде. При следующем вызове функции итератора выполнение возобновляется с этого места.
Для завершения итерации можно использовать оператор yield break.
Дополнительные сведения об итераторах см. в разделе Итераторы (C# и Visual Basic).
Методы итератора и методы доступа get
Объявление итератора должно соответствовать следующим требованиям.
Возвращаемый тип должен быть IEnumerable, IEnumerable, IEnumerator или IEnumerator.
Тип yield итератора, который возвращает IEnumerable или IEnumerator, — object. Если итератор возвращает IEnumerable или IEnumerator, необходимо выполнить неявное преобразование из типа выражения в операторе yield return в параметр универсального типа.
Ниже указаны методы, в которых операторы yield return и yield break использовать нельзя.
Анонимные методы. Дополнительные сведения см. в разделе Анонимные методы (Руководство по программированию в C#).
Методы, содержащие небезопасные блоки. Дополнительные сведения см. в разделе unsafe (Справочник по C#).
Обработка исключений
Оператор yield return нельзя размещать в блоке try-catch. Оператор yield return можно размещать в блоке try оператора try-finally.
Оператор yield break можно размещать в блоке try или catch, но не в блоке finally.
Если тело оператора foreach (вне метода итератора) вызывает исключение, выполняется блок finally в методе итератора.
Техническая реализация
В следующем коде возвращается объект IEnumerable<string> из метода итератора и затем выполняется перебор его элементов.
IEnumerable<string> elements = MyIteratorMethod();
foreach (string element in elements)
{
…
}
При вызове MyIteratorMethod тело метода не выполняется. Вместо этого вызов возвращает IEnumerable<string> в переменную elements.
В итерации цикла foreach метод MoveNext вызывается для elements. Этот вызов выполняет тело MyIteratorMethod до достижения следующего оператора yield return. Выражение, возвращаемое оператором yield return, определяет не только значение переменной element для использования телом цикла, но и свойство Current элементов, представляющее собой IEnumerable<string>.
В каждой последующей итерации цикла foreach выполнение тела итератора продолжается с места остановки и при достижении оператора yield return оно снова останавливается. Цикл foreach завершается при достижении конца метода итератора или оператора yield break.
Пример
В следующем примере имеется оператор yield return, расположенный в цикле for. Каждая итерация тела оператора foreach в Process создает вызов функции итератора Power. При каждом вызове функции итератора происходит переход к следующему выполнению оператора yield return, которое осуществляется во время следующей итерации цикла for.
Возвращаемый тип метода итератора — IEnumerable (тип интерфейса итератора). При вызове метода итератора возвращается перечисляемый объект, содержащий степени числа.
public class PowersOf2
{
static void Main()
{
// Display powers of 2 up to the exponent of 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
{
int result = 1;
for (int i = 0; i < exponent; i++)
{
result = result * number;
yield return result;
}
}
// Output: 2 4 8 16 32 64 128 256
}
В следующем примере демонстрируется метод доступа get, представляющий собой итератор. В этом примере каждый оператор yield return возвращает экземпляр пользовательского класса.
public static class GalaxyClass
{
public static void ShowGalaxies()
{
var theGalaxies = new Galaxies();
foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy)
{
Debug.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString());
}
}
public class Galaxies
{
public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy
{
get
{
yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
}
}
}
public class Galaxy
{
public String Name { get; set; }
public int MegaLightYears { get; set; }
}
}
Спецификация языка C#
Дополнительные сведения см. в Спецификация языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
См. также
Ссылки
foreach, in (Справочник по C#)
Основные понятия
Руководство по программированию на C#