Delen via


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 de foreach 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 een unsafe blok. Vanaf C# 13 kunt yield u gebruiken in methoden met unsafe blokken, maar niet in het unsafe blok.
  • yield return en yield break kan niet worden gebruikt in catch en ten slotte blokken, of in try-blokken met een corresponderend catch blok. De yield return en yield break instructies kunnen worden gebruikt in een try blok zonder catch blokken, alleen een finally 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.

Zie ook