Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
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
GetEnumeratoruntuk mengaktifkan iterasi atas instans jenis denganforeachpernyataan , 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 dalam parameter, ref, atau keluar.
- ekspresi lambda dan metode anonim .
-
blok tidak aman. Sebelum C# 13,
yieldtidak valid dalam metode apa pun denganunsafeblok. Dimulai dengan C# 13, Anda dapat menggunakanyielddalam metode denganunsafeblok, tetapi tidak diunsafeblok. -
yield returndanyield breaktidak dapat digunakan dalam menangkap dan akhirnya memblokir, atau di blok percobaan dengan blok yang sesuaicatch. Pernyataanyield returndanyield breakdapat digunakan dalamtryblok tanpacatchblok, hanya blokfinally.
using pernyataan dalam iterator
Anda dapat menggunakan using pernyataan dalam metode iterator. Karena using pernyataan dikompilasi ke dalam try blok dengan finally klausul (dan tidak ada catch blok), pernyataan berfungsi dengan benar dengan iterator. Sumber daya sekali pakai dikelola dengan benar selama eksekusi iterator:
Console.WriteLine("=== Using in Iterator Example ===");
// Demonstrate that using statements work correctly in iterators
foreach (string line in ReadLinesFromResource())
{
Console.WriteLine($"Read: {line}");
// Simulate processing only first two items
if (line == "Line 2") break;
}
Console.WriteLine("Iteration stopped early - resource should still be disposed.");
static IEnumerable<string> ReadLinesFromResource()
{
Console.WriteLine("Opening resource...");
using var resource = new StringWriter(); // Use StringWriter as a simple IDisposable
resource.WriteLine("Resource initialized");
// These lines would typically come from the resource (e.g., file, database)
string[] lines = { "Line 1", "Line 2", "Line 3", "Line 4" };
foreach (string line in lines)
{
Console.WriteLine($"About to yield: {line}");
yield return line;
Console.WriteLine($"Resumed after yielding: {line}");
}
Console.WriteLine("Iterator completed - using block will dispose resource.");
}
Seperti yang ditunjukkan oleh contoh sebelumnya, sumber daya yang diperoleh dalam using pernyataan tetap tersedia di seluruh eksekusi iterator, bahkan ketika iterator menangguhkan dan melanjutkan eksekusi pada yield return pernyataan. Sumber daya dibuang ketika iterator selesai (baik dengan mencapai akhir atau melalui yield break) atau ketika iterator itu sendiri dibuang (misalnya, ketika penelepon keluar dari enumerasi lebih awal).
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#.