Saya memiliki keraguan tentang bagaimana Enumerator bekerja, dan LINQ. Pertimbangkan dua pilihan sederhana ini:
List<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct().ToList();
atau
IEnumerable<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct();
Saya mengubah nama-nama objek asli saya sehingga ini terlihat seperti contoh yang lebih umum. Permintaan itu sendiri tidak begitu penting. Yang ingin saya tanyakan adalah ini:
foreach (Animal animal in sel) { /*do stuff*/ }
Saya perhatikan bahwa jika saya menggunakan
IEnumerable
, ketika saya men-debug dan memeriksa "sel", yang dalam hal ini adalah IEnumerable, ia memiliki beberapa anggota yang menarik: "dalam", "luar", "innerKeySelector" dan "outerKeySelector", 2 terakhir ini muncul menjadi delegasi. Anggota "batin" tidak memiliki instance "Hewan" di dalamnya, melainkan instance "Spesies", yang sangat aneh bagi saya. Anggota "luar" memang mengandung instance "Hewan". Saya berasumsi bahwa kedua delegasi menentukan mana yang masuk dan apa yang keluar dari sana?Saya perhatikan bahwa jika saya menggunakan "Distinct", "inner" berisi 6 item (ini tidak benar karena hanya 2 yang Distinct), tetapi "outer" memang mengandung nilai yang benar. Sekali lagi, mungkin metode yang didelegasikan menentukan ini, tetapi ini sedikit lebih dari yang saya tahu tentang IEnumerable.
Yang paling penting, yang mana dari dua opsi ini yang terbaik untuk kinerja?
Konversi daftar jahat melalui .ToList()
?
Atau mungkin menggunakan enumerator secara langsung?
Jika Anda bisa, tolong jelaskan juga sedikit atau lempar beberapa tautan yang menjelaskan penggunaan IEnumerable ini.
sumber
IEnumerable<T>
akan menjadi LINQ-To-Objects setelah bagian pertama yang berarti semua yang terlihat harus dikembalikan untuk menjalankan Feline. Di sisi lain,IQuertable<T>
akan memungkinkan kueri disempurnakan, hanya menarik Spines Felines yang turun.Ada artikel yang sangat bagus yang ditulis oleh: Claudio Bernasconi's TechBlog di sini: Kapan menggunakan IEnumerable, ICollection, IList and List
Di sini beberapa dasar menunjukkan tentang skenario dan fungsi:
sumber
List
merupakan implementasi dariIList
dan dengan demikian memiliki fungsi tambahan di atas mereka yangIList
(misalnyaSort
,Find
,InsertRange
). Jika Anda memaksakan diri untuk menggunakanIList
lebihList
, Anda kehilangan metode ini yang mungkin Anda perlukanIReadOnlyCollection<T>
[]
sini.Kelas yang mengimplementasikan
IEnumerable
memungkinkan Anda untuk menggunakanforeach
sintaks.Pada dasarnya ia memiliki metode untuk mendapatkan item berikutnya dalam koleksi. Tidak perlu seluruh koleksi berada di memori dan tidak tahu berapa banyak item di dalamnya,
foreach
terus dapatkan item berikutnya sampai habis.Ini bisa sangat berguna dalam keadaan tertentu, misalnya dalam tabel database besar Anda tidak ingin menyalin semuanya ke dalam memori sebelum Anda mulai memproses baris.
Sekarang
List
mengimplementasikanIEnumerable
, tetapi mewakili seluruh koleksi dalam memori. Jika Anda memilikiIEnumerable
dan menelepon,.ToList()
Anda membuat daftar baru dengan isi enumerasi dalam memori.Ekspresi LINQ Anda mengembalikan enumerasi, dan secara default ekspresi dieksekusi ketika Anda beralih menggunakan
foreach
. SebuahIEnumerable
mengeksekusi pernyataan LINQ ketika Anda iterateforeach
, tetapi Anda dapat memaksa untuk iterate lebih cepat menggunakan.ToList()
.Inilah yang saya maksud:
sumber
foreach
sementara Daftar akan pergi dengan mengatakan indeks. Sekarang, jika saya ingin tahu jumlah / panjang darithing
sebelumnya, IEnumerable tidak akan membantu, kan?List
danArray
implementasikanIEnumerable
. Anda dapat menganggapnyaIEnumerable
sebagai penyebut umum terendah yang berfungsi baik dalam koleksi memori maupun yang besar yang mendapatkan satu item sekaligus. Ketika Anda menelepon,IEnumerable.Count()
Anda mungkin menelepon.Length
properti cepat atau melalui seluruh koleksi - intinya adalah bahwaIEnumerable
Anda tidak tahu. Itu bisa menjadi masalah, tetapi jika Anda hanya akan melakukannyaforeach
maka Anda tidak peduli - kode Anda akan bekerja denganArray
atauDataReader
sama.Tidak ada yang menyebutkan satu perbedaan penting, ironisnya menjawab pertanyaan yang ditutup sebagai duplikat dari ini.
Lihat Perbedaan praktis antara Daftar dan IEnumerable
sumber
Hal yang paling penting untuk disadari adalah bahwa, menggunakan Linq, permintaan tidak segera dievaluasi. Hal ini hanya dijalankan sebagai bagian dari iterasi melalui dihasilkan
IEnumerable<T>
dalamforeach
- yang ini apa semua delegasi aneh lakukan.Jadi, contoh pertama mengevaluasi permintaan segera dengan memanggil
ToList
dan memasukkan hasil permintaan dalam daftar.Contoh kedua mengembalikan sebuah
IEnumerable<T>
yang berisi semua informasi yang diperlukan untuk menjalankan kueri nanti.Dalam hal kinerja, jawabannya tergantung . Jika Anda ingin hasil dievaluasi sekaligus (misalnya, Anda mengubah struktur yang Anda tanyakan nanti, atau jika Anda tidak ingin iterasi lebih
IEnumerable<T>
lama dari itu) gunakan daftar. Lain gunakanIEnumerable<T>
. Defaultnya adalah menggunakan evaluasi sesuai permintaan dalam contoh kedua, karena yang umumnya menggunakan lebih sedikit memori, kecuali ada alasan khusus untuk menyimpan hasil dalam daftar.sumber
Join
melakukan itu bekerja - dalam dan luar adalah dua sisi bergabung. Secara umum, jangan khawatir tentang apa yang sebenarnya ada diIEnumerables
dalamnya, karena akan sangat berbeda dari kode Anda yang sebenarnya. Hanya khawatir tentang output aktual ketika Anda mengulanginya :)Keuntungan dari IEnumerable adalah eksekusi yang ditangguhkan (biasanya dengan database). Permintaan tidak akan dieksekusi sampai Anda benar-benar mengulang data. Ini permintaan menunggu sampai dibutuhkan (alias pemuatan malas).
Jika Anda memanggil ToList, kueri akan dieksekusi, atau "terwujud" seperti yang ingin saya katakan.
Ada pro dan kontra untuk keduanya. Jika Anda memanggil ToList, Anda dapat menghapus beberapa misteri ketika kueri dieksekusi. Jika Anda tetap menggunakan IEnumerable, Anda mendapatkan keuntungan bahwa program tidak melakukan pekerjaan apa pun sampai itu benar-benar diperlukan.
sumber
Saya akan membagikan satu konsep yang disalahgunakan yang saya masukkan ke dalam satu hari:
Hasil yang diharapkan
Hasil yang sebenarnya
Penjelasan
Sebagai jawaban lain, evaluasi hasil ditunda sampai memanggil
ToList
atau metode doa serupa misalnyaToArray
.Jadi saya dapat menulis ulang kode dalam hal ini sebagai:
Mainkan di sekeliling
https://repl.it/E8Ki/0
sumber
IEnumerable
kerjanya, tapi sekarang Bukankah lebih karena saya tahu;)Jika semua yang ingin Anda lakukan adalah menghitungnya, gunakan
IEnumerable
.Namun berhati-hatilah bahwa mengubah koleksi asli yang disebutkan adalah operasi yang berbahaya - dalam hal ini, Anda ingin melakukannya
ToList
terlebih dahulu. Ini akan membuat elemen daftar baru untuk setiap elemen dalam memori, menghitungIEnumerable
dan dengan demikian kurang berkinerja jika Anda hanya menghitung satu kali - tetapi lebih aman dan kadang-kadangList
metode yang berguna (misalnya dalam akses acak).sumber
IEnumerable
, kemudian membuat daftar terlebih dahulu (dan mengulangi itu) berarti Anda mengulangi elemen dua kali . Jadi kecuali Anda ingin melakukan operasi yang lebih efisien dalam daftar, ini benar-benar berarti kinerja yang lebih rendah..ToList()
bantu di sini;)Selain semua jawaban yang diposting di atas, berikut adalah dua sen saya. Ada banyak tipe lain selain List yang mengimplementasikan IEnumerable seperti ICollection, ArrayList, dll. Jadi jika kita memiliki IEnumerable sebagai parameter dari metode apa pun, kita bisa meneruskan semua tipe koleksi ke fungsi. Yaitu kita dapat memiliki metode untuk beroperasi pada abstraksi bukan implementasi spesifik.
sumber
Ada banyak kasus (seperti daftar tak terbatas atau daftar yang sangat besar) di mana IEnumerable tidak dapat diubah menjadi Daftar. Contoh yang paling jelas adalah semua bilangan prima, semua pengguna facebook dengan detailnya, atau semua item di ebay.
Perbedaannya adalah bahwa "Daftar" objek disimpan "di sini dan sekarang", sedangkan "IEnumerable" objek bekerja "hanya satu per satu". Jadi, jika saya memeriksa semua item di ebay, satu per satu akan menjadi sesuatu yang bahkan dapat ditangani oleh komputer kecil, tetapi ".ToList ()" pasti akan membuat saya kehabisan memori, tidak peduli seberapa besar komputer saya. Tidak ada komputer yang dapat dengan sendirinya memuat dan menangani data dalam jumlah sangat besar.
[Sunting] - Tidak perlu dikatakan - itu bukan "ini atau itu". seringkali masuk akal untuk menggunakan daftar dan IEnumerable di kelas yang sama. Tidak ada komputer di dunia yang dapat mendaftar semua bilangan prima, karena menurut definisi ini akan membutuhkan jumlah memori yang tak terbatas. Tetapi Anda dapat dengan mudah memikirkan
class PrimeContainer
yang berisiIEnumerable<long> primes
, yang karena alasan yang jelas juga mengandungSortedList<long> _primes
. semua bilangan prima dihitung sejauh ini. perdana berikutnya yang akan diperiksa hanya akan dijalankan terhadap bilangan prima yang ada (hingga akar kuadrat). Dengan begitu Anda memperoleh keduanya - bilangan prima satu per satu (IEnumerable) dan daftar "bilangan prima sejauh ini" yang bagus, yang merupakan perkiraan yang cukup bagus dari seluruh daftar (tak terbatas).sumber