rendementsinstructie - geef het volgende element op
U gebruikt de yield
instructie in een iterator om de volgende waarde op te geven of het einde van een iteratie aan te geven. De yield
instructie heeft de twee volgende formulieren:
yield return
: om de volgende waarde in iteratie op te geven, zoals in het volgende voorbeeld wordt weergegeven: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
: om het einde van de iteratie expliciet aan te geven, zoals in het volgende voorbeeld wordt weergegeven: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; } } }
Iteratie wordt ook voltooid wanneer het besturingselement het einde van een iterator bereikt.
In de voorgaande voorbeelden is IEnumerable<T> het retourtype iterators (in niet-generische gevallen gebruikt IEnumerable u als retourtype van een iterator). U kunt ook als retourtype van een iterator gebruiken IAsyncEnumerable<T> . Dat maakt een iterator asynchroon. Gebruik de await foreach
instructie om het resultaat van iterator te herhalen, zoals in het volgende voorbeeld wordt weergegeven:
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> of IEnumerator kan ook het retourtype van een iterator zijn. Gebruik deze retourtypen wanneer u de GetEnumerator
methode in de volgende scenario's implementeert:
U ontwerpt het type dat implementeert IEnumerable<T> of IEnumerable interface implementeert.
U voegt een exemplaar- of extensiemethode
GetEnumerator
toe om iteratie in te schakelen voor het exemplaar van het type met deforeach
instructie, zoals in het volgende voorbeeld wordt weergegeven: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; } }
U kunt de yield
instructies niet gebruiken in:
- methoden met in-, verw- of outparameters
- lambda-expressies en anonieme methoden
- onveilige blokken. Vóór C# 13 was
yield
deze ongeldig in een methode met eenunsafe
blok. Vanaf C# 13 kuntyield
u gebruiken in methoden metunsafe
blokken, maar niet in hetunsafe
blok. yield return
enyield break
kan niet worden gebruikt in catch en ten slotte blokken, of in try-blokken met een corresponderendcatch
blok. Deyield return
enyield break
instructies kunnen worden gebruikt in eentry
blok zondercatch
blokken, alleen eenfinally
blok.
Uitvoering van een iterator
De aanroep van een iterator wordt niet onmiddellijk uitgevoerd, zoals in het volgende voorbeeld wordt weergegeven:
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.
Zoals in het voorgaande voorbeeld wordt weergegeven, wordt een iterator uitgevoerd wanneer u het resultaat van een iterator begint te herhalen totdat de eerste yield return
instructie is bereikt. Vervolgens wordt de uitvoering van een iterator onderbroken en krijgt de aanroeper de eerste iteratiewaarde en verwerkt deze. Bij elke volgende iteratie wordt de uitvoering van een iterator hervat na de instructie die de yield return
vorige schorsing heeft veroorzaakt en gaat door totdat de volgende yield return
instructie is bereikt. De iteratie wordt voltooid wanneer het besturingselement het einde van een iterator of een yield break
instructie bereikt.
C#-taalspecificatie
Zie de sectie Rendementsinstructie van de C#-taalspecificatie voor meer informatie.