Adakah yang bisa menjelaskan IEnumerable dan IEnumerator kepada saya?
misalnya, kapan menggunakannya lebih dulu? apa perbedaan antara IEnumerable dan IEnumerator? Mengapa kita perlu menggunakannya?
c#
ienumerable
ienumerator
prodev42
sumber
sumber
Jawaban:
Anda tidak menggunakan
IEnumerable
"lebih"foreach
. PelaksanaIEnumerable
membuat menggunakanforeach
mungkin .Ketika Anda menulis kode seperti:
itu secara fungsional setara dengan menulis:
Dengan "setara secara fungsional," Maksud saya sebenarnya kompiler mengubah kode menjadi. Anda tidak dapat menggunakan
foreach
padabaz
dalam contoh ini kecualibaz
alatIEnumerable
.IEnumerable
berartibaz
mengimplementasikan metodeThe
IEnumerator
objek yang metode ini kembali harus menerapkan metodedan
Metode pertama maju ke objek berikutnya di
IEnumerable
objek yang membuat enumerator, kembalifalse
jika sudah selesai, dan yang kedua mengembalikan objek saat ini.Apa pun di .Net yang dapat Anda ulangi dari implementasinya
IEnumerable
. Jika Anda membangun kelas Anda sendiri, dan itu belum mewarisi dari kelas yang mengimplementasikanIEnumerable
, Anda dapat membuat kelas Anda dapat digunakan dalamforeach
pernyataan dengan menerapkanIEnumerable
(dan dengan membuat kelas enumerator bahwaGetEnumerator
metode baru akan kembali).sumber
bool MoveNext()
metode danCurrent
properti tipe apa pun. Pendekatan "mengetik bebek" ini diterapkan di C # 1.0 sebagai cara untuk menghindari tinju ketika menghitung koleksi tipe nilai.iterator
?Antarmuka IEnumerable dan IEnumerator
Untuk mulai memeriksa proses penerapan antarmuka .NET yang ada, mari kita lihat peran IEnumerable dan IEnumerator. Ingatlah bahwa C # mendukung kata kunci bernama foreach yang memungkinkan Anda untuk mengulangi isi dari jenis array apa pun:
Meskipun mungkin terlihat bahwa hanya tipe array yang dapat menggunakan konstruk ini, kebenaran dari masalahnya adalah semua tipe yang mendukung metode bernama GetEnumerator () dapat dievaluasi oleh konstruk foreach. Untuk menggambarkan, ikuti saya!
Misalkan kita memiliki kelas Garasi:
Idealnya, akan lebih mudah untuk beralih di atas subtitle objek Garage menggunakan konstruksi foreach, seperti array nilai data:
Sayangnya, kompiler memberi tahu Anda bahwa kelas Garage tidak mengimplementasikan metode bernama GetEnumerator (). Metode ini diformalkan oleh antarmuka IEnumerable, yang ditemukan bersembunyi di dalam namespace System.Collections. Kelas atau struktur yang mendukung perilaku ini mengiklankan bahwa mereka dapat mengekspos subitem yang terkandung ke pemanggil (dalam contoh ini, kata kunci foreach itu sendiri). Berikut adalah definisi antarmuka .NET standar ini:
Seperti yang Anda lihat, metode GetEnumerator () mengembalikan referensi ke antarmuka lain bernama System.Collections.IEnumerator. Antarmuka ini menyediakan infrastruktur untuk memungkinkan pemanggil melintasi objek internal yang terkandung oleh wadah yang kompatibel dengan IEnumerable:
Jika Anda ingin memperbarui tipe Garage untuk mendukung antarmuka ini, Anda bisa menempuh jalan panjang dan mengimplementasikan setiap metode secara manual. Meskipun Anda tentu saja bebas untuk menyediakan versi GetEnumerator (), MoveNext (), Current, dan Reset () yang disesuaikan, ada cara yang lebih sederhana. Karena tipe System.Array (dan juga banyak kelas koleksi lainnya) sudah mengimplementasikan IEnumerable dan IEnumerator, Anda bisa mendelegasikan permintaan ke System.Array sebagai berikut:
Setelah Anda memperbarui tipe Garage, Anda dapat menggunakan tipe itu dengan aman di dalam konstruksi C # foreach. Selanjutnya, mengingat bahwa metode GetEnumerator () telah didefinisikan secara publik, pengguna objek juga dapat berinteraksi dengan tipe IEnumerator:
Namun, jika Anda lebih suka menyembunyikan fungsi IEnumerable dari tingkat objek, cukup gunakan implementasi antarmuka eksplisit:
Dengan melakukannya, pengguna objek biasa tidak akan menemukan metode GetEnumerator () Garage, sedangkan konstruksi foreach akan mendapatkan antarmuka di latar belakang bila diperlukan.
Diadaptasi dari Pro C # 5.0 dan .NET 4.5 Framework
sumber
Garage
yang didapatcarArray
? Dengan begitu Anda tidak perlu menerapkanGetEnumerator
sendiri, karenaArray
sudah melakukan ini. Misalnyaforeach(Car c in carLot.getCars()) { ... }
Menerapkan IEnumerable berarti kelas Anda mengembalikan objek IEnumerator:
Menerapkan IEnumerator berarti kelas Anda mengembalikan metode dan properti untuk iterasi:
Itulah bedanya.
sumber
Penjelasan melalui Analogi + Panduan Kode
Pertama, penjelasan tanpa kode, lalu saya tambahkan nanti.
Katakanlah Anda menjalankan perusahaan penerbangan. Dan di setiap pesawat Anda ingin mengetahui informasi tentang penumpang yang terbang di pesawat. Pada dasarnya Anda ingin dapat "melintasi" pesawat. Dengan kata lain, Anda ingin dapat mulai di kursi depan, dan kemudian berjalan ke bagian belakang pesawat, menanyakan beberapa penumpang informasi: siapa mereka, dari mana mereka berasal dll. Pesawat terbang hanya dapat melakukan ini , jika memang:
Mengapa persyaratan ini? Karena itulah yang diperlukan antarmuka.
Jika ini adalah informasi yang berlebihan, yang perlu Anda ketahui adalah bahwa Anda ingin dapat mengajukan beberapa pertanyaan kepada setiap penumpang di pesawat, mulai dari yang pertama dan berjalan ke yang terakhir.
Apa artinya dihitung?
Jika sebuah maskapai penerbangan "dapat dihitung", ini berarti bahwa HARUS ada pramugari yang hadir di pesawat, yang tugas satu-satunya adalah menghitung - dan pramugari ini HARUS menghitung dengan cara yang sangat spesifik:
Prosedur Penghitungan
Kapten maskapai menginginkan laporan tentang setiap penumpang ketika dan ketika mereka diselidiki atau dihitung. Jadi setelah berbicara dengan orang yang duduk di kursi pertama, pramugari / konter kemudian melapor kepada kapten, dan ketika laporan diberikan, konter mengingat posisi tepatnya di lorong dan terus menghitung tepat di mana dia pergi mati.
Dengan cara ini kapten selalu dapat memiliki informasi tentang orang yang sedang diselidiki. Dengan begitu, jika dia mengetahui bahwa orang ini menyukai Manchester City, maka dia dapat memberikan perlakuan istimewa pada penumpang tersebut, dll.
Mari kita ikat ini dengan IEnumerables
Seorang enumerable hanyalah kumpulan penumpang di pesawat. Hukum Penerbangan Sipil - ini pada dasarnya adalah aturan yang harus diikuti oleh semua jumlah IEnumerable. Setiap kali pramugari pergi ke kapten dengan informasi penumpang, kami pada dasarnya 'menyerahkan' penumpang ke kapten. Kapten pada dasarnya dapat melakukan apapun yang dia inginkan dengan penumpang - kecuali mengatur ulang penumpang di pesawat. Dalam hal ini, mereka diberikan perlakuan istimewa jika mereka mengikuti Manchester City (ugh!)
Ringkasan
Dengan kata lain, sesuatu dapat diperhitungkan jika memiliki penghitung . Dan kontra keharusan (pada dasarnya): (i) ingat tempatnya ( state ), (ii) dapat bergerak ke depan , (iii) dan tahu tentang saat orang yang ia berurusan dengan.
Enumerable hanyalah sebuah kata mewah untuk "countable". Dengan kata lain, enumerable memungkinkan Anda untuk 'menghitung' (yaitu menghitung).
sumber
IEnumerable mengimplementasikan GetEnumerator. Ketika dipanggil, metode itu akan mengembalikan IEnumerator yang mengimplementasikan MoveNext, Reset dan Current.
Jadi ketika kelas Anda mengimplementasikan IEnumerable, Anda mengatakan bahwa Anda dapat memanggil metode (GetEnumerator) dan mendapatkan objek baru yang dikembalikan (sebuah IEnumerator) yang dapat Anda gunakan dalam satu loop seperti foreach.
sumber
Menerapkan IEnumerable memungkinkan Anda untuk mendapatkan IEnumerator untuk daftar.
IEnumerator memungkinkan akses berurutan gaya foreach ke item dalam daftar, menggunakan kata kunci hasil.
Sebelum implementasi foreach (di Java 1.4, misalnya), cara untuk mengulang daftar adalah untuk mendapatkan enumerator dari daftar, kemudian meminta item "berikutnya" dalam daftar, selama nilai dikembalikan sebagai yang berikutnya item bukan nol. Foreach hanya melakukan itu secara implisit sebagai fitur bahasa, dengan cara yang sama yang mengunci () mengimplementasikan kelas Monitor di belakang layar.
Saya berharap foreach bekerja pada daftar karena mereka mengimplementasikan IEnumerable.
sumber
Pikirkan benda yang bisa dihitung sebagai daftar, tumpukan, pohon.
sumber
IEnumerable dan IEnumerator (dan rekan-rekan generik mereka IEnumerable <T> dan IEnumerator <T>) adalah antarmuka dasar dari implementasi iterator di koleksi .Net Framework Class Libray .
IEnumerable adalah antarmuka paling umum yang akan Anda lihat di sebagian besar kode di luar sana. Ini memungkinkan foreach loop, generator (think yield ) dan karena antarmuka yang kecil, ini digunakan untuk membuat abstraksi yang ketat. IEnumerable tergantung pada IEnumerator .
IEnumerator , di sisi lain, menyediakan antarmuka iterasi yang sedikit lebih rendah. Ini disebut sebagai iterator eksplisit yang memberi programmer lebih banyak kontrol atas siklus iterasi.
Tidak terhitung
IEnumerable adalah antarmuka standar yang memungkinkan pengulangan koleksi yang mendukungnya (pada kenyataannya, semua jenis koleksi yang dapat saya pikirkan saat ini mengimplementasikan IEnumerable ). Dukungan kompiler memungkinkan fitur bahasa seperti
foreach
. Secara umum, ini memungkinkan implementasi iterator implisit ini .foreach Loop
Saya pikir
foreach
loop adalah salah satu alasan utama untuk menggunakan antarmuka IEnumerable .foreach
memiliki sintaksis yang sangat ringkas dan sangat mudah dipahami dibandingkan dengan gaya C klasik untuk loop di mana Anda perlu memeriksa berbagai variabel untuk melihat apa yang dilakukannya.menghasilkan kata kunci
Mungkin fitur yang kurang diketahui adalah bahwa IEnumerable juga memungkinkan generator di C # dengan penggunaan
yield return
danyield break
pernyataan.Abstraksi
Skenario umum lainnya dalam praktik adalah menggunakan IEnumerable untuk memberikan abstraksi minimalis. Karena itu adalah antarmuka sangat kecil dan hanya-baca, Anda didorong untuk mengekspos koleksi Anda sebagai IEnumerable (bukan List misalnya). Dengan begitu Anda bebas untuk mengubah implementasi Anda tanpa melanggar kode klien Anda (misalnya, ubah Daftar ke LinkedList ).
Kena kau
Satu perilaku yang harus diperhatikan adalah bahwa dalam implementasi streaming (mis. Mengambil data baris demi baris dari database, alih-alih memuat semua hasil dalam memori terlebih dahulu) Anda tidak dapat mengulangi koleksi lebih dari sekali. Ini berbeda dengan koleksi dalam memori seperti Daftar , di mana Anda dapat mengulangi beberapa kali tanpa masalah. ReSharper, misalnya, memiliki inspeksi kode untuk kemungkinan enumerasi ganda dari IEnumerable .
IEnumerator
IEnumerator, di sisi lain, adalah antarmuka di belakang layar yang membuat IEnumerble-foreach-magic bekerja. Sebenarnya, ini memungkinkan iterator eksplisit.
Dalam pengalaman saya, IEnumerator jarang digunakan dalam skenario umum karena sintaksisnya lebih verbose dan semantik yang sedikit membingungkan (setidaknya bagi saya; eg MoveNext () mengembalikan nilai juga, yang namanya tidak disarankan sama sekali).
Gunakan case untuk IEnumerator
Saya hanya menggunakan IEnumerator di perpustakaan (kerangka yang sedikit lebih rendah) dan kerangka kerja di mana saya menyediakan antarmuka IEnumerable . Salah satu contoh adalah pustaka pemrosesan aliran data yang menyediakan serangkaian objek dalam satu
foreach
lingkaran meskipun di balik layar data dikumpulkan menggunakan berbagai aliran file dan serialisasi.Kode klien
Perpustakaan
sumber
Menerapkan
IEnumerable
pada dasarnya berarti bahwa objek dapat diulangi. Ini tidak selalu berarti array karena ada daftar tertentu yang tidak dapat diindeks tetapi Anda dapat menghitungnya.IEnumerator
adalah objek aktual yang digunakan untuk melakukan iterasi. Ini mengontrol bergerak dari satu objek ke yang berikutnya dalam daftar.Sebagian besar waktu,
IEnumerable
&IEnumerator
digunakan secara transparan sebagai bagian dariforeach
loop.sumber
Perbedaan antara IEnumerable dan IEnumerator:
Setiap kali kami meneruskan koleksi IEnumerable ke fungsi lain, ia tidak tahu posisi item / objek saat ini (tidak tahu item mana yang dieksekusi)
IEnumerable memiliki satu metode GetEnumerator ()
IEnumerator memiliki satu properti yang disebut Current dan dua metode, Reset () dan MoveNext () (yang berguna untuk mengetahui posisi item saat ini dalam daftar).
sumber
IEnumerable adalah kotak yang berisi Ienumerator. IEnumerable adalah antarmuka dasar untuk semua koleksi. foreach loop dapat beroperasi jika koleksi mengimplementasikan IEnumerable. Dalam kode di bawah ini menjelaskan langkah memiliki Enumerator kita sendiri. Pertama-tama mari kita tentukan Kelas kita yang akan kita buat koleksi.
Sekarang kita akan mendefinisikan Kelas yang akan bertindak sebagai koleksi untuk Pelanggan kelas kita. Perhatikan bahwa itu mengimplementasikan antarmuka IEnumerable. Sehingga kita harus mengimplementasikan metode GetEnumerator. Ini akan mengembalikan Enumerator khusus kami.
Sekarang kita akan membuat Enumerator khusus kita sendiri sebagai berikut. Jadi, kita harus mengimplementasikan metode MoveNext.
Sekarang kita bisa menggunakan foreach loop pada koleksi kita seperti di bawah ini;
sumber
Pemahaman tentang pola Iterator akan membantu Anda. Saya sarankan membaca yang sama.
Pola Iterator
Pada tingkat tinggi, pola iterator dapat digunakan untuk memberikan cara pengulangan standar melalui koleksi jenis apa pun. Kami memiliki 3 peserta dalam pola iterator, koleksi aktual (klien), agregator dan iterator. Agregat adalah kelas antarmuka / abstrak yang memiliki metode yang mengembalikan iterator. Iterator adalah kelas antarmuka / abstrak yang memiliki metode yang memungkinkan kita untuk beralih melalui koleksi.
Untuk menerapkan pola pertama-tama kita perlu menerapkan iterator untuk menghasilkan beton yang dapat diulang atas koleksi yang bersangkutan (klien). Kemudian koleksi (klien) mengimplementasikan agregator untuk mengembalikan instance dari iterator di atas.
Berikut adalah diagram UML
Jadi pada dasarnya dalam c #, IEnumerable adalah agregat abstrak dan IEnumerator adalah Iterator abstrak. IEnumerable memiliki metode tunggal GetEnumerator yang bertanggung jawab untuk membuat instance IEnumerator dari tipe yang diinginkan. Koleksi seperti Daftar menerapkan IEnumerable.
Contoh. Mari kita anggap kita memiliki metode
getPermutations(inputString)
yang mengembalikan semua permutasi string dan metode mengembalikan contohIEnumerable<string>
Untuk menghitung jumlah permutasi, kita dapat melakukan sesuatu seperti di bawah ini.
Kompiler c # kurang lebih mengubah konversi di atas menjadi
Jika Anda memiliki pertanyaan, jangan ragu untuk bertanya.
sumber
Kontribusi minor.
Seperti banyak dari mereka menjelaskan tentang 'kapan harus menggunakan' dan 'gunakan dengan foreach'. Saya berpikir untuk menambahkan Perbedaan Negara Lain di sini seperti yang diminta dalam pertanyaan tentang perbedaan antara kedua IEnumerable dan IEnumerator.
Saya membuat contoh kode di bawah ini berdasarkan utas diskusi di bawah ini.
IEnumerable, IEnumerator vs foreach, kapan harus menggunakan apa perbedaan antara IEnumerator dan IEnumerable?
Enumerator mempertahankan status (posisi iterasi) antara panggilan fungsi sementara iterasi sebaliknya Enumerable tidak.
Berikut adalah contoh yang diuji dengan komentar untuk dipahami.
Para ahli harap tambahkan / koreksi saya.
sumber
Saya perhatikan perbedaan-perbedaan ini:
A. Kita mengulang daftar dengan cara yang berbeda, foreach dapat digunakan untuk IEnumerable dan while loop untuk IEnumerator.
B. IEnumerator dapat mengingat indeks saat ini ketika kami beralih dari satu metode ke metode lain (ini mulai bekerja dengan indeks saat ini) tetapi IEnumerable tidak dapat mengingat indeks dan mereset indeks ke awal. Lebih banyak di video ini https://www.youtube.com/watch?v=jd3yUjGc9M0
sumber
IEnumerable
danIEnumerator
keduanya adalah antarmuka dalam C #.IEnumerable
adalah antarmuka yang mendefinisikan metode tunggalGetEnumerator()
yang mengembalikanIEnumerator
antarmuka.Ini berfungsi untuk akses hanya baca ke koleksi yang mengimplementasikan yang
IEnumerable
dapat digunakan denganforeach
pernyataan.IEnumerator
memiliki dua metode,MoveNext
danReset
. Ini juga memiliki properti yang disebutCurrent
.Berikut ini menunjukkan implementasi IEnumerable dan IEnumerator.
sumber
sumber