Diberikan kode ini:
IEnumerable<object> FilteredList()
{
foreach( object item in FullList )
{
if( IsItemInPartialList( item ) )
yield return item;
}
}
Mengapa saya tidak harus hanya kode seperti ini ?:
IEnumerable<object> FilteredList()
{
var list = new List<object>();
foreach( object item in FullList )
{
if( IsItemInPartialList( item ) )
list.Add(item);
}
return list;
}
Saya agak mengerti apa yang dilakukan yield
kata kunci. Ini memberitahu kompiler untuk membangun hal tertentu (sebuah iterator). Tapi mengapa menggunakannya? Terlepas dari itu kode yang sedikit kurang, apa fungsinya bagi saya?
FullList.Where(IsItemInPartialList)
:)Jawaban:
Menggunakan
yield
membuat koleksi malas.Katakanlah Anda hanya membutuhkan lima item pertama. Cara Anda, saya harus mengulang seluruh daftar untuk mendapatkan lima item pertama. Dengan
yield
, saya hanya mengulang lima item pertama.sumber
FullList.Where(IsItemInPartialList)
akan sama malasnya. Hanya saja, ia membutuhkan jauh lebih sedikit kompiler yang dihasilkan kode kustom --- gunk ---. Dan kurang waktu pengembang menulis dan memelihara. (Tentu saja, itu hanya contoh ini)yield return
) jika memungkinkan.Keuntungan dari blok iterator adalah mereka bekerja dengan malas. Jadi, Anda dapat menulis metode pemfilteran seperti ini:
Itu akan memungkinkan Anda untuk menyaring aliran selama Anda suka, tidak pernah buffer lebih dari satu item pada suatu waktu. Jika Anda hanya membutuhkan nilai pertama dari urutan yang dikembalikan, misalnya, mengapa Anda ingin menyalin semuanya ke daftar baru?
Sebagai contoh lain, Anda dapat dengan mudah membuat aliran tanpa batas menggunakan blok iterator. Misalnya, inilah urutan angka acak:
Bagaimana Anda menyimpan urutan yang tak terbatas dalam daftar?
Seri blog Edulinq saya memberikan contoh implementasi LINQ ke Objek yang banyak menggunakan blok iterator. LINQ pada dasarnya malas di mana ia bisa - dan meletakkan segala sesuatu dalam daftar tidak berfungsi seperti itu.
sumber
RandomSequence
atau tidak. Bagi saya, IEnumerable berarti -pertama dan terpenting- yang bisa saya ulangi dengan foreach, tetapi ini jelas akan menyebabkan loop yang tidak terbatas di sini. Saya akan menganggap ini sebagai penyalahgunaan konsep IEnumerable yang sangat berbahaya, tetapi YMMV.IEnumerable<BigInteger>
mewakili urutan Fibonacci, misalnya. Anda dapat menggunakannyaforeach
dengan itu, tetapi tidak adaIEnumerable<T>
jaminan bahwa itu akan terbatas.Dengan kode "daftar", Anda harus memproses daftar lengkap sebelum dapat meneruskannya ke langkah berikutnya. Versi "hasil" langsung melewati item yang diproses ke langkah berikutnya. Jika "langkah selanjutnya" berisi ". Ambil (10)" maka versi "hasil" hanya akan memproses 10 item pertama dan melupakan sisanya. Kode "daftar" akan memproses semuanya.
Ini berarti bahwa Anda melihat perbedaan paling besar ketika Anda perlu melakukan banyak pemrosesan dan / atau memiliki daftar panjang item untuk diproses.
sumber
Anda dapat menggunakan
yield
untuk mengembalikan item yang tidak ada dalam daftar. Berikut adalah sedikit contoh yang dapat diulang tanpa batas hingga daftar dibatalkan.Ini menulis
... dll. ke konsol sampai dibatalkan.
sumber
Ketika kode di atas digunakan untuk mengulang melalui FilteredList () dan dengan asumsi item.Name == "James" akan dipenuhi pada item ke-2 dalam daftar, metode yang menggunakan
yield
akan menghasilkan dua kali. Ini adalah perilaku malas.Sedangkan metode menggunakan daftar akan menambahkan semua objek ke daftar dan meneruskan daftar lengkap ke metode panggilan.
Ini persis kasus penggunaan di mana perbedaan antara IEnumerable dan IList dapat disorot.
sumber
Contoh dunia nyata terbaik yang pernah saya lihat untuk penggunaan
yield
adalah menghitung urutan Fibonacci.Pertimbangkan kode berikut:
Ini akan mengembalikan:
Ini bagus karena memungkinkan Anda untuk menghitung seri yang tak terbatas dengan cepat dan mudah, memberi Anda kemampuan untuk menggunakan ekstensi Linq dan hanya meminta apa yang Anda butuhkan.
sumber
Terkadang bermanfaat, kadang tidak. Jika seluruh rangkaian data harus diperiksa dan dikembalikan maka tidak akan ada manfaat dalam menggunakan hasil karena semua yang dilakukannya hanyalah memperkenalkan overhead.
Ketika hasil benar-benar bersinar adalah ketika hanya sebagian parsial dikembalikan. Saya pikir contoh terbaik adalah menyortir. Asumsikan Anda memiliki daftar objek yang berisi tanggal dan jumlah dolar dari tahun ini dan Anda ingin melihat segelintir (5) catatan pertama tahun ini.
Untuk mencapai ini, daftar harus disortir naik berdasarkan tanggal, dan kemudian diambil 5 yang pertama. Jika ini dilakukan tanpa hasil, seluruh daftar harus disortir, hingga memastikan dua tanggal terakhir sudah beres.
Namun, dengan hasil, setelah 5 item pertama telah ditetapkan penyortiran berhenti dan hasilnya tersedia. Ini dapat menghemat banyak waktu.
sumber
Pernyataan pengembalian hasil memungkinkan Anda untuk mengembalikan hanya satu item pada suatu waktu. Anda mengumpulkan semua item dalam daftar dan kembali mengembalikan daftar itu, yang merupakan overhead memori.
sumber