Megosztás a következőn keresztül:


hozamkimutatás – adja meg a következő elemet

Az iterátorbanyieldutasí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ássalforeach 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 blokkot unsafe tartalmazó metódusban. A C# 13-tól kezdve blokkokkal rendelkező yield metódusokban használhatóunsafe, blokkokban unsafe azonban nem.
  • yield returnés yield break nem használható fogásiés végül blokkok, vagy próbálja blokkok egy megfelelő catch blokk. Az yield return és yield break az utasítások blokkok nélkültry, csak blokkokban catch 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.

Lásd még