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([2, 3, 4, 5, -1, 3, 4])));
    // Output: 2 3 4 5
    
    Console.WriteLine(string.Join(" ", TakeWhilePositive([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-algemene 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. Dit is handig 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 extensiemethodeGetEnumerator 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:

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