Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Gebruik 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.
De C#-taalreferentiedocumenten de laatst uitgebrachte versie van de C#-taal. Het bevat ook de eerste documentatie voor functies in openbare previews voor de aanstaande taalrelease.
De documentatie identificeert alle functies die voor het eerst zijn geïntroduceerd in de laatste drie versies van de taal of in de huidige openbare previews.
Aanbeveling
Raadpleeg het artikel over de versiegeschiedenis van de C#-taal om te achterhalen wanneer een functie voor het eerst is geïntroduceerd in C#.
In de voorgaande voorbeelden is IEnumerable<T>het retourtype iterators. Gebruik in niet-genrische gevallen IEnumerable als het 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 toe om iteratie in te schakelen voor het exemplaar van het type met de
GetEnumerator, 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, ref, of uit parameters.
- lambda-expressies en anonieme methoden.
-
onveilige blokken. Vóór C# 13 was
yielddeze ongeldig in een methode met eenunsafeblok. Vanaf C# 13 kuntyieldu gebruiken in methoden metunsafeblokken, maar niet in hetunsafeblok. -
yield returnenyield breakkan niet worden gebruikt in catch en ten slotte blokken, of in try-blokken met een corresponderendcatchblok. Deyield returnenyield breakinstructies kunnen worden gebruikt in eentryblok zondercatchblokken, alleen eenfinallyblok.
using instructies in iterators
U kunt instructies gebruiken using in iteratormethoden. Omdat using instructies worden gecompileerd in try blokken met finally componenten (en geen catch blokken), werken ze correct met iterators. De wegwerpresources worden correct beheerd tijdens de uitvoering van de iterator:
Console.WriteLine("=== Using in Iterator Example ===");
// Demonstrate that using statements work correctly in iterators
foreach (string line in ReadLinesFromResource())
{
Console.WriteLine($"Read: {line}");
// Simulate processing only first two items
if (line == "Line 2") break;
}
Console.WriteLine("Iteration stopped early - resource should still be disposed.");
static IEnumerable<string> ReadLinesFromResource()
{
Console.WriteLine("Opening resource...");
using var resource = new StringWriter(); // Use StringWriter as a simple IDisposable
resource.WriteLine("Resource initialized");
// These lines would typically come from the resource (e.g., file, database)
string[] lines = { "Line 1", "Line 2", "Line 3", "Line 4" };
foreach (string line in lines)
{
Console.WriteLine($"About to yield: {line}");
yield return line;
Console.WriteLine($"Resumed after yielding: {line}");
}
Console.WriteLine("Iterator completed - using block will dispose resource.");
}
Zoals in het voorgaande voorbeeld wordt weergegeven, blijft de resource die in de using instructie is verkregen beschikbaar gedurende de uitvoering van de iterator, zelfs wanneer de iterator de uitvoering bij yield return instructies onderbreekt en hervat. De resource wordt verwijderd wanneer de iterator is voltooid (ofwel door het einde of via yield break) te bereiken of wanneer de iterator zelf wordt verwijderd (bijvoorbeeld wanneer de aanroeper vroeg uit opsomming uitvalt).
Uitvoering van een iterator
Als u een iterator aanroept, wordt deze 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 de iterator uitgevoerd totdat de eerste yield return instructie is bereikt wanneer u het resultaat van een iterator begint te herhalen. Vervolgens wordt de uitvoering van de iterator onderbroken en krijgt de aanroeper de eerste iteratiewaarde en verwerkt deze. Bij elke volgende iteratie wordt de uitvoering van de 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.