pernyataan hasil - berikan elemen berikutnya

Anda menggunakan yield pernyataan dalam iterator untuk memberikan nilai berikutnya atau memberi sinyal akhir perulangan. Pernyataan ini yield memiliki dua formulir berikut:

  • yield return: untuk memberikan nilai berikutnya dalam iterasi, seperti yang ditunjukkan contoh berikut:

    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: untuk secara eksplisit memberi sinyal akhir iterasi, seperti yang ditunjukkan contoh berikut:

    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;
            }
        }
    }
    

    Iterasi juga selesai ketika kontrol mencapai akhir iterator.

Dalam contoh sebelumnya, jenis pengembalian iterator adalah IEnumerable<T> (dalam kasus non-generik, gunakan IEnumerable sebagai jenis pengembalian iterator). Anda juga dapat menggunakan IAsyncEnumerable<T> sebagai jenis pengembalian iterator. Itu membuat asinkron iterator. await foreach Gunakan pernyataan untuk melakukan iterasi atas hasil iterator, seperti yang ditunjukkan contoh berikut:

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> atau IEnumerator juga bisa menjadi jenis pengembalian iterator. Itu berguna ketika Anda menerapkan GetEnumerator metode dalam skenario berikut:

  • Anda merancang jenis yang mengimplementasikan IEnumerable<T> atau IEnumerable antarmuka.

  • Anda menambahkan instans atau metode ekstensiGetEnumerator untuk mengaktifkan iterasi atas instans jenis dengan foreach pernyataan , seperti yang ditunjukkan contoh berikut:

    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;
        }
    }
    

Anda tidak dapat menggunakan yield pernyataan di:

Eksekusi iterator

Panggilan iterator tidak segera menjalankannya, seperti yang ditunjukkan contoh berikut:

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.

Seperti yang ditunjukkan contoh sebelumnya, ketika Anda mulai melakukan iterasi atas hasil iterator, iterator dijalankan hingga pernyataan pertama yield return tercapai. Kemudian, eksekusi iterator ditangguhkan dan pemanggil mendapatkan nilai iterasi pertama dan memprosesnya. Pada setiap iterasi berikutnya, eksekusi iterator dilanjutkan setelah yield return pernyataan yang menyebabkan penangguhan sebelumnya dan berlanjut hingga pernyataan berikutnya yield return tercapai. Iterasi selesai ketika kontrol mencapai akhir iterator atau yield break pernyataan.

Spesifikasi bahasa C#

Untuk informasi selengkapnya, lihat bagian Pernyataan hasil dari spesifikasi bahasa C#.

Lihat juga