hozamkimutatás – adja meg a következő elemet
Az iterátorbanyield
utasítással adja meg a következő értéket, vagy jelezheti az iteráció végét. Az yield
utasítás a következő két űrlapot tartalmazza:
yield return
: a következő értéket adja meg az iterációban, ahogy az alábbi példa is mutatja:foreach (int i in ProduceEvenNumbers(9)) { Console.Write(i); Console.Write(" "); } // Output: 0 2 4 6 8 IEnumerable<int> ProduceEvenNumbers(int upto) { for (int i = 0; i <= upto; i += 2) { yield return i; } }
yield break
: az iteráció befejezésének explicit jelzése, ahogy az alábbi példa is mutatja:Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] {2, 3, 4, 5, -1, 3, 4}))); // Output: 2 3 4 5 Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] {9, 8, 7}))); // Output: 9 8 7 IEnumerable<int> TakeWhilePositive(IEnumerable<int> numbers) { foreach (int n in numbers) { if (n > 0) { yield return n; } else { yield break; } } }
Az iteráció akkor is befejeződik, ha a vezérlő eléri az iterátor végét.
Az előző példákban az iterátorok IEnumerable<T> visszatérési típusa (nemgenerikus esetekben az iterátor visszatérési típusaként használható IEnumerable ). Az iterátor visszatérési típusaként is használható IAsyncEnumerable<T> . Ez egy iterátor aszinkron lesz.
await foreach
Az utasítás használatával iterálhatja az iterátor eredményét, ahogy az alábbi példa is mutatja:
await foreach (int n in GenerateNumbersAsync(5))
{
Console.Write(n);
Console.Write(" ");
}
// Output: 0 2 4 6 8
async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
for (int i = 0; i < count; i++)
{
yield return await ProduceNumberAsync(i);
}
}
async Task<int> ProduceNumberAsync(int seed)
{
await Task.Delay(1000);
return 2 * seed;
}
IEnumerator<T> vagy IEnumerator egy iterátor visszatérési típusa is lehet. Ezeket a visszatérési típusokat akkor használja, ha a metódust GetEnumerator
a következő forgatókönyvekben implementálja:
A megvalósító IEnumerable<T> vagy IEnumerable interfész típust kell megtervezni.
Az utasítással
foreach
típuspéldányon, ahogy az alábbi példa is mutatja:public static void Example() { var point = new Point(1, 2, 3); foreach (int coordinate in point) { Console.Write(coordinate); Console.Write(" "); } // Output: 1 2 3 } public readonly record struct Point(int X, int Y, int Z) { public IEnumerator<int> GetEnumerator() { yield return X; yield return Y; yield return Z; } }
A következő utasítások nem használhatók yield
:
- metódusok a -ban, hivatkozással a -ra, vagy kimeneti paramétereken.
- lambda kifejezések és névtelen metódusok.
-
nem biztonságos blokkok. A C# 13
yield
előtt érvénytelen volt bármely blokkotunsafe
tartalmazó metódusban. A C# 13-tól kezdve blokkokkal rendelkezőyield
metódusokban használhatóunsafe
, blokkokbanunsafe
azonban nem. -
yield return
ésyield break
nem használható fogásiés végül blokkok, vagy próbálja blokkok egy megfelelőcatch
blokk. Azyield return
ésyield break
az utasítások blokkok nélkültry
, csak blokkokbancatch
használhatókfinally
.
Iterátor végrehajtása
Az iterátor hívása nem hajtja végre azonnal, ahogy az alábbi példa is mutatja:
var numbers = ProduceEvenNumbers(5);
Console.WriteLine("Caller: about to iterate.");
foreach (int i in numbers)
{
Console.WriteLine($"Caller: {i}");
}
IEnumerable<int> ProduceEvenNumbers(int upto)
{
Console.WriteLine("Iterator: start.");
for (int i = 0; i <= upto; i += 2)
{
Console.WriteLine($"Iterator: about to yield {i}");
yield return i;
Console.WriteLine($"Iterator: yielded {i}");
}
Console.WriteLine("Iterator: end.");
}
// Output:
// Caller: about to iterate.
// Iterator: start.
// Iterator: about to yield 0
// Caller: 0
// Iterator: yielded 0
// Iterator: about to yield 2
// Caller: 2
// Iterator: yielded 2
// Iterator: about to yield 4
// Caller: 4
// Iterator: yielded 4
// Iterator: end.
Ahogy az előző példa is mutatja, amikor egy iterátor eredménye fölött kezd iterálni, a rendszer addig hajt végre egy iterátort, amíg el nem éri az első yield return
utasítást. Ezután az iterátor végrehajtása fel lesz függesztve, és a hívó megkapja az első iterációs értéket, és feldolgozza azt. Minden további iteráció esetében az iterátor végrehajtása az előző felfüggesztést okozó utasítás után yield return
folytatódik, és a következő yield return
utasítás eléréséig folytatódik. Az iteráció akkor fejeződik be, amikor a vezérlő eléri az iterátor vagy egy yield break
utasítás végét.
C# nyelvspecifikáció
További információ: A C# nyelv specifikációjának hozamkimutatási szakasza.