Perbedaan antara berbagai Antarmuka Generik Koleksi di C #

11

Saya telah bermain-main dengan C # untuk Windows dan pengembangan ASP.net MVC untuk beberapa waktu sekarang. Tapi saya masih belum jelas di beberapa daerah. Saya mencoba memahami perbedaan mendasar antara dan masalah kinerja dengan menggunakan dan menukar jenis Antarmuka Koleksi Generik yang serupa .

Apa perbedaan mendasar antara IEnumerable<T>, ICollection<T>, List<T>(Class)?

Saya tampaknya menggunakan dan menukarnya tanpa melihat ada masalah dalam aplikasi saya. Juga, apakah ada koleksi generik yang lebih mirip seperti ini yang dapat dipertukarkan dengan ketiganya?

Pankaj Upadhyay
sumber
2
ada juga IList <T> juga
jk.

Jawaban:

19

List <T> adalah kelas dan mengimplementasikan antarmuka ICollection <T> dan IEnumerable <T> . Juga, ICollection <T> memperluas antarmuka IEnumerable <T>. Mereka tidak dapat dipertukarkan, setidaknya tidak dari semua sudut pandang.

Jika Anda memiliki Daftar <T>, Anda dijamin bahwa objek ini mengimplementasikan metode dan properti yang diperlukan untuk diterapkan oleh antarmuka ICollection <T> dan IEnumerable <T>. Kompiler mengetahuinya dan Anda diizinkan untuk melemparkannya ke ICollection <T> atau IEnumerable <T> secara implisit. Namun, jika Anda memiliki ICollection <T> Anda harus memeriksa secara eksplisit dalam kode Anda terlebih dahulu apakah itu Daftar <T> atau yang lain, mungkin Kamus <T> (di mana T adalah KeyValuePair ) sebelum memberikannya ke apa yang Anda keinginan.

Anda tahu bahwa ICollection memperluas IEnumerable, sehingga Anda bisa melemparkannya ke IEnumerable. Tetapi jika Anda hanya memiliki IEnumerable, sekali lagi Anda tidak dijamin bahwa itu adalah Daftar. Mungkin saja, tetapi bisa juga sesuatu yang lain. Anda harus mengharapkan pengecualian pemain tidak valid jika Anda mencoba untuk melemparkan Daftar <T> ke Kamus <T> misalnya.

Jadi mereka tidak "dipertukarkan".

Juga, ada banyak antarmuka generik, lihat apa yang dapat Anda temukan di System.Collections . namespace umum.

Sunting: mengenai komentar Anda, sama sekali tidak ada penalti kinerja jika Anda menggunakan Daftar <T> atau salah satu antarmuka yang diterapkannya. Anda masih perlu membuat objek baru, periksa kode berikut:

List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;

daftar , myColl , dan myEnum semuanya menunjuk ke objek yang sama. Apakah Anda mendeklarasikannya sebagai Daftar atau ICollection atau IEnumerable, saya masih memerlukan program untuk membuat Daftar. Saya bisa menulis ini:

ICollection<T> myColl = new List<T>();

myColl , saat runtime masih menjadi Daftar.

Namun , ini adalah poin yang paling penting ... untuk mengurangi kopling dan meningkatkan pemeliharaan Anda harus selalu mendeklarasikan variabel dan parameter metode Anda menggunakan penyebut serendah mungkin yang mungkin bagi Anda, apakah itu antarmuka atau kelas abstrak atau konkret.

Bayangkan bahwa satu-satunya hal yang dibutuhkan metode "PerformOperation" adalah untuk menghitung elemen, melakukan pekerjaan dan keluar, dalam hal ini Anda tidak memerlukan ratusan metode yang tersedia di Daftar <T>, Anda hanya perlu apa yang tersedia di IEnumerable <T >, jadi yang berikut harus berlaku:

public void PerformOperation(IEnumerable<T> myEnumeration) { ... }

Dengan melakukan itu, Anda dan pengembang lainnya tahu bahwa objek apa pun dari kelas yang mengimplementasikan antarmuka <n> IEnumerable dapat diberikan ke metode ini. Ini mungkin Daftar, Kamus, atau kelas koleksi khusus yang ditulis pengembang lain.

Jika sebaliknya Anda menentukan Anda secara eksplisit membutuhkan Daftar konkret <T> (dan meskipun jarang terjadi dalam kehidupan nyata, hal itu masih dapat terjadi), Anda dan pengembang lainnya tahu bahwa itu haruslah Daftar atau kelas konkret lain yang mewarisi dari Daftar.

Jalayn
sumber
Pertama-tama, terima kasih. Sekarang, titik perhatiannya adalah bagaimana memutuskan mana yang akan digunakan ??. Karena List <T> mengimplementasikan kedua antarmuka, mengapa tidak selalu menggunakannya di setiap tempat di mana IEnumerable atau ICollection diperlukan. Akankah selalu menggunakan daftar memiliki dampak kinerja? Harap edit jawaban Anda untuk membalas masalah ini
Pankaj Upadhyay
Saya diedit untuk menjawab pertanyaan kinerja Anda
Jalayn 8/11
+1, tetapi saya akan menambahkan bahwa dalam kasus langka di mana Anda benar-benar membutuhkan untuk meneruskan daftar ke suatu metode, Anda harus menggunakan IListdaripada Listdalam deklarasi metode.
Konamiman
@Konamiman - Tergantung jika Anda membutuhkan List<>fungsi khusus, seperti .AddRange(). Tidak IList<>mengungkap itu.
Bobson
6

Lihat halaman MSDN untuk ICollection dan IEnumerable .

Dalam istilah yang sangat abstrak, beginilah cara saya memahami tipe-tipe ini.

IEnumerable adalah segala sesuatu yang dapat disebutkan - yaitu, diulangi. Itu tidak selalu berarti 'koleksi'; misalnya, sebuah IQueryable mengimplementasikan IEnumerable dan itu bukan koleksi, tetapi adalah sesuatu yang dapat diminta untuk mengembalikan objek. Untuk mengimplementasikan IEnumerable, objek hanya perlu dapat mengembalikan objek saat ditanya. Saya mungkin mengatakan bahwa saya memiliki banyak tugas yang akan saya lakukan hari ini (ini bukan daftar karena saya belum menuliskannya atau merumuskannya, tetapi saya dapat memberi tahu Anda apa yang akan saya lakukan sekarang, dan jika Anda bertanya 'dan kemudian?' Saya akan dapat memberi tahu Anda tugas berikut).

Sebuah ICollection lebih konkret daripada IEnumerable. Perbedaan utama adalah bahwa suatu Koleksi tahu berapa banyak item yang dikandungnya; untuk mengetahui berapa banyak item dalam Enumerable, Anda secara efektif mengulang dan menghitungnya:

Saya: Guys, berapa banyak item yang Anda masing-masing miliki di dalam kamu?

Enumerable: Saya tidak begitu tahu. Nah, ini satu item. Saya punya satu lagi, jadi itu dua. Dan satu lagi, jadi itu tiga ... dan satu lagi ... ok jadi itu 2382. Tidak ada lagi item, jadi saya punya 2382. Jangan tanya lagi kepada saya karena saya harus memeriksa semuanya lagi.

Koleksi: Saya punya 2382 item. Saya sudah tahu itu.

Koleksi biasanya sesuatu yang sudah tahu di mana semua elemennya, dan tidak perlu pergi dan menemukan atau menghasilkan mereka ketika Anda meminta mereka. Ini lebih ... konkret daripada Enumerable.

Menurut pendapat saya perbedaan antara Enumerable dan Koleksi jauh lebih besar daripada perbedaan antara Koleksi dan Daftar. Sebenarnya saya berjuang untuk memikirkan perbedaan praktis antara Koleksi dan Daftar, tetapi saya yakin Daftar menyediakan metode yang lebih baik untuk mencari dan memesan.

Jenis Koleksi lainnya termasuk Queuedan Stack, juga Dictionary.

Nama-nama jenis ini cukup berguna - Anda dapat membayangkan antrian dan tumpukan sebagai rekan dunia nyata mereka, dan mempertimbangkan perbedaan yang mungkin Anda miliki dalam Daftar.

Kirk Broadhurst
sumber
"Saya berjuang untuk memikirkan perbedaan praktis antara Koleksi dan Daftar" ... Kemudian dalam jawaban Anda, Anda menjawabnya sendiri. Sebuah Listadalah ICollection, tetapi ICollectiontidak selalu List( Queue, Stack, Dictionary, ...)
Steven Jeuris
@ Sebelas Ini jawaban yang sangat bertele-tele. Saya setuju bahwa ini adalah perbedaan penting, tetapi saya tidak akan menyebutnya perbedaan praktis. Apa artinya bagi pengguna?
Kirk Broadhurst
Itu mudah! :) Queue<int> queue = (Queue<int>)list;akan melempar InvalidCastExceptionketika listbukan Queue<int>. Perbedaan antara antrian dan daftar di luar cakupan untuk pertanyaan ini.
Steven Jeuris
Bukan aspek kritis dari IEnumerable yang dapat mengembalikan item saat ini dan berikutnya - Anda semacam menyinggung itu, tetapi jangan secara eksplisit mengatakannya. Pada dasarnya sesuatu yang mengimplementasikan IEnumerable saja tidak dapat mengembalikan item sewenang-wenang anggotanya ketika ditanya - hanya yang saat ini dan yang berikutnya.
cori
@cori Itu cara yang sangat ringkas untuk menjelaskannya, jauh lebih jelas daripada jawaban saya.
Kirk Broadhurst
-1

IQueryable:

kueri tidak dieksekusi sampai benar-benar beralih pada item, mungkin dengan melakukan .ToList ()

Tidak terhitung:

hanya meneruskan daftar item. Anda tidak bisa mendapatkan "item 4" tanpa melewati item 0-3. daftar hanya-baca, Anda tidak dapat menambah atau menghapusnya. Masih mungkin menggunakan eksekusi yang ditangguhkan.

Tidak ada:

akses acak ke daftar lengkap seluruhnya dalam memori mendukung penambahan dan penghapusan

ICollection:

Apakah antara IEnumerable dan IList. Apa yang "terbaik" tergantung pada kebutuhan Anda. Biasanya meskipun IEnumerable "cukup baik" jika Anda hanya ingin menampilkan item. Setidaknya selalu gunakan varian generik.

Zia Qammar
sumber
jawaban ini tampaknya tidak menambah sesuatu yang berharga dari apa yang sudah diposting di jawaban sebelumnya
agas
itu hanya konsep sederhana tentang semua
Zia Qammar