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(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; } } }
Iterasi juga selesai ketika kontrol mencapai akhir iterator.
Dalam contoh sebelumnya, jenis pengembalian iterator adalah IEnumerable<T> (dalam kasus nongenerik, 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. Gunakan jenis pengembalian tersebut GetEnumerator
saat Anda menerapkan metode dalam skenario berikut:
Anda merancang jenis yang mengimplementasikan IEnumerable<T> atau IEnumerable antarmuka.
Anda menambahkan instans atau metode ekstensi
GetEnumerator
untuk mengaktifkan iterasi atas instans jenis denganforeach
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:
- metode dengan parameter masuk, ref, atau keluar
- ekspresi lambda dan metode anonim
- blok tidak aman. Sebelum C# 13,
yield
tidak valid dalam metode apa pun denganunsafe
blok. Dimulai dengan C# 13, Anda dapat menggunakanyield
dalam metode denganunsafe
blok, tetapi tidak diunsafe
blok. yield return
danyield break
tidak dapat digunakan dalam percobaan, menangkap dan akhirnya memblokir.
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#.