Mengapa menggunakan ICollection dan bukan IEnumerable atau List <T> pada banyak-banyak / satu-banyak hubungan?

359

Saya melihat ini banyak dalam tutorial, dengan properti navigasi sebagai ICollection<T>.

Apakah ini persyaratan wajib untuk Kerangka Entitas? Bisakah saya menggunakan IEnumerable?

Apa tujuan utama menggunakan ICollectionbukan IEnumerableatau bahkan List<T>?

Jan Carlo Viray
sumber

Jawaban:

440

Biasanya apa yang Anda pilih akan bergantung pada metode mana yang perlu Anda akses. Secara umum - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx ) untuk daftar objek yang hanya perlu diulangi, ICollection<>(MSDN: http: // msdn.microsoft.com/en-us/library/92t2ye13.aspx ) untuk daftar objek yang perlu diiterasi dan dimodifikasi, List<>untuk daftar objek yang perlu diulang melalui, dimodifikasi, disortir, dll (Lihat di sini untuk daftar lengkap: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx ).

Dari sudut pandang yang lebih spesifik, lazy loading masuk untuk bermain dengan memilih tipe. Secara default, properti navigasi di Entity Framework datang dengan pelacakan perubahan dan adalah proksi. Agar proxy dinamis dibuat sebagai properti navigasi, tipe virtual harus diimplementasikan ICollection.

Properti navigasi yang mewakili ujung "banyak" dari suatu hubungan harus mengembalikan tipe yang mengimplementasikan ICollection, di mana T adalah jenis objek di ujung lain dari hubungan. - Persyaratan untuk Membuat POCO Proxies MSDN

Informasi lebih lanjut tentang Mendefinisikan dan Mengelola Hubungan MSDN

Travis J
sumber
2
jadi, dengan itu, Listharusnya jauh lebih baik, ya?
Jan Carlo Viray
3
@ JanCarloViray - Saya cenderung Listbanyak menggunakan . Meskipun memiliki overhead paling banyak, ia menyediakan fungsionalitas paling banyak.
Travis J
1
Daftar didefinisikan lebih oleh pengindeksnya daripada oleh kemampuan untuk mengurutkannya (memiliki pengindeks integer memudahkan untuk mengurutkan sesuatu, tetapi itu bukan keharusan).
phoog
2
Sehubungan dengan pengeditan Anda, membatasi properti ke jenis antarmuka bukan tentang memori tetapi tentang enkapsulasi. Pertimbangkan: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };gunakan memori yang sama denganprivate List<int> _integers = new List<int> { 1, 2, 3 };
phoog
13
@ TravisJ: List<T>memiliki GetEnumerator()metode, terpisah dari implementasinya IEnumerable<T>, yang mengembalikan tipe struktur yang bisa berubah List<T>.Enumerator. Dalam sebagian besar konteks, tipe itu akan menghasilkan kinerja yang sedikit lebih baik daripada objek tumpukan mandiri. Kompiler yang menggunakan enumerator tipe bebek (seperti yang dilakukan oleh C # dan vb.net) dapat memanfaatkan hal ini saat membuat foreachkode. Jika List<T>dilemparkan ke IEnumrable<T>sebelum foreach, IEnumerable<T>.GetEnumerator()metode akan mengembalikan objek yang dialokasikan tumpukan, membuat optimasi tidak mungkin.
supercat
86

ICollection<T>digunakan karena IEnumerable<T>antarmuka tidak menyediakan cara untuk menambahkan item, menghapus item, atau memodifikasi koleksi.

Justin Niessner
sumber
3
bagaimana dengan membandingkan dengan Daftar <T>?
Jan Carlo Viray
12
List<T>mengimplementasikan ICollection<T>.
pemboros
Non-generik ICollectiontidak memungkinkan cara apa pun untuk menambahkan item, tetapi masih merupakan tambahan yang berguna IEnumerable<T>karena memberikan Countanggota yang biasanya jauh lebih cepat daripada menghitung semuanya. Perhatikan bahwa jika suatu IList<Cat>atau ICollection<Cat>diteruskan ke kode mengharapkan suatu IEnumerable<Animal>, Count()metode ekstensi akan cepat jika mengimplementasikan non-generik ICollection, tetapi tidak jika hanya mengimplementasikan antarmuka generik karena tipikal ICollection<Cat>tidak akan mengimplementasikan ICollection<Animal>.
supercat
58

Menanggapi pertanyaan Anda tentang List<T>:

List<T>adalah kelas; menentukan antarmuka memungkinkan lebih banyak fleksibilitas implementasi. Pertanyaan yang lebih baik adalah "mengapa tidak IList<T>?"

Untuk menjawab pertanyaan itu, pertimbangkan apa yang IList<T>ditambahkan ke ICollection<T>: pengindeksan bilangan bulat, yang berarti item memiliki beberapa perintah arbitrer, dan dapat diambil dengan merujuk pada urutan itu. Ini mungkin tidak berarti dalam banyak kasus, karena barang mungkin perlu dipesan secara berbeda dalam konteks yang berbeda.

phoog
sumber
21

Ada beberapa perbedaan mendasar antara ICollection dan IEnumerable

  • IEnumerable - hanya berisi metode GetEnumerator untuk mendapatkan Enumerator dan memungkinkan perulangan
  • ICollection berisi metode tambahan: Tambah, Hapus, Berisi, Hitung, CopyTo
  • ICollection diwarisi dari IEnumerable
  • Dengan ICollection Anda dapat memodifikasi koleksi dengan menggunakan metode seperti menambah / menghapus. Anda tidak memiliki kebebasan untuk melakukan hal yang sama dengan IEnumerable.

Program sederhana:

using System;
using System.Collections;
using System.Collections.Generic;

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Jack", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}
Ramakrishnan
sumber
13

Saya mengingatnya seperti ini:

  1. IEnumerable memiliki satu metode GetEnumerator () yang memungkinkan seseorang untuk membaca nilai-nilai dalam koleksi tetapi tidak menulisnya. Sebagian besar kerumitan menggunakan enumerator diurus untuk kita oleh untuk setiap pernyataan dalam C #. IEnumerable memiliki satu properti: Current, yang mengembalikan elemen saat ini.

  2. ICollection mengimplementasikan IEnumerable dan menambahkan beberapa properti tambahan yang paling banyak digunakan adalah Count. Versi umum dari ICollection mengimplementasikan metode Add () dan Remove ().

  3. IList mengimplementasikan IEnumerable dan ICollection, dan menambahkan akses pengindeksan bilangan bulat ke item (yang biasanya tidak diperlukan, karena pemesanan dilakukan dalam database).

pengguna3918295
sumber
4
Berdasarkan apa yang Anda tulis, ICollection dan IList adalah sama. Silakan tambahkan apa yang ditambahkan ke IList yang tidak ada di ICollection.
Taruhan
ICollection VS IList, antarmuka hanya IList di System.Collection yang berisi semua fungsi IEnumerable dan ICollection dan fungsionalitas tambahan. IList memiliki metode Sisipkan dan Hapus. Kedua metode menerima indeks dalam parameter mereka. Jadi, ini mendukung operasi berbasis indeks alih-alih pengumpulan.
E. Meir
7

Ide dasar penggunaan ICollectionadalah menyediakan antarmuka untuk hanya membaca-akses ke sejumlah data yang terbatas. Bahkan Anda memiliki properti ICollection.Count . IEnumerablelebih cocok untuk beberapa rantai data di mana Anda membaca sampai beberapa titik logis, suatu kondisi yang secara spesifik ditentukan oleh konsumen atau sampai akhir enumerasi.

Tigran
sumber
14
TIL yang ICollectionhanya-baca sementara ICollection<T>tidak.
Carl G
2

Properti navigasi biasanya didefinisikan sebagai virtual sehingga mereka dapat memanfaatkan fungsionalitas Entity Framework tertentu seperti pemuatan malas.

Jika properti navigasi dapat menampung banyak entitas (seperti dalam hubungan banyak ke banyak atau satu ke banyak), jenisnya harus berupa daftar di mana entri dapat ditambahkan, dihapus, dan diperbarui, seperti ICollection.

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net- aplikasi mvc

LewisAntonio803
sumber
2

Apa yang telah saya lakukan di masa lalu adalah mendeklarasikan koleksi kelas dalam saya menggunakan IList<Class>, ICollection<Class>atau IEnumerable<Class>(jika daftar statis) tergantung pada apakah saya harus melakukan sejumlah hal berikut atau tidak dalam metode dalam repositori saya: enumerate, sort / order atau memodifikasi . Ketika saya hanya perlu menghitung (dan mungkin mengurutkan) objek maka saya membuat temp List<Class>untuk bekerja dengan koleksi dalam metode IEnumerable. Saya pikir praktik ini hanya akan efektif jika koleksinya relatif kecil, tetapi mungkin praktik yang baik secara umum, idk. Harap perbaiki saya jika ada bukti mengapa ini tidak akan menjadi praktik yang baik.

yardpenalty.com
sumber
0

Mari kita coba berpikir di luar kotak dengan / oleh logika dan mengerti dengan jelas ketiga antarmuka dalam pertanyaan Anda:

Ketika kelas dari beberapa instance mengimplementasikan antarmuka System.Collection.IEnumerable maka, dengan kata-kata sederhana, kita dapat mengatakan bahwa instance ini keduanya enumerable dan iterable, yang berarti bahwa instance ini memungkinkan entah bagaimana dalam satu loop tunggal untuk pergi / mendapatkan / lulus / melintasi / beralih atas / melalui semua item dan elemen yang berisi instance ini.

Ini berarti bahwa ini juga memungkinkan untuk menyebutkan semua item dan elemen yang terdapat dalam instance ini.

Setiap kelas yang mengimplementasikan antarmuka System.Collection.IEnumerable juga mengimplementasikan metode GetEnumerator yang tidak menggunakan argumen dan mengembalikan instance System.Collections.IEnumerator.

Contoh antarmuka System.Collections.IEnumerator berperilaku sangat mirip dengan iterator C ++.

Ketika kelas beberapa instance mengimplementasikan antarmuka System.Collection.ICollection maka, dengan kata-kata sederhana, kita dapat mengatakan bahwa instance ini adalah beberapa kumpulan hal.

Versi generik dari antarmuka ini, yaitu System.Collection.Generic.ICollection, lebih informatif karena antarmuka generik ini secara eksplisit menyatakan apa jenis barang dalam koleksi.

Ini semua masuk akal, rasional, logis dan masuk akal bahwa System.Collections.ICollection interface mewarisi dari System.Collections.Intermuka yang dapat dihitung, karena secara teoritis setiap koleksi juga dapat dihitung dan diulang dan secara teori ini mungkin untuk membahas semua item dan elemen di setiap koleksi.

Antarmuka System.Collections.ICollection mewakili koleksi dinamis terbatas yang dapat diubah, yang berarti bahwa item yang ada dapat dihapus dari koleksi dan item baru dapat ditambahkan ke koleksi yang sama.

Ini menjelaskan mengapa antarmuka System.Collections.ICollection memiliki metode "Tambah" dan "Hapus".

Karena instance antarmuka System.Collections.ICollection adalah koleksi hingga maka kata "hingga" menyiratkan bahwa setiap koleksi antarmuka ini selalu memiliki jumlah item dan elemen yang terbatas di dalamnya.

Properti Count dari System.Collections.ICollection antarmuka mengandaikan untuk mengembalikan nomor ini.

Antarmuka System.Collections.IEnumerable tidak memiliki metode dan properti yang dimiliki antarmuka System.Collections.ICollection, karena tidak masuk akal bahwa System.Collections.IEnumerable akan memiliki metode dan properti yang memiliki antarmuka System.Collections.ICollection.

Logikanya juga mengatakan bahwa setiap instance yang enumerable dan iterable tidak harus berupa koleksi dan tidak harus berubah.

Ketika saya mengatakan dapat diubah, maksud saya jangan langsung berpikir bahwa Anda dapat menambah atau menghapus sesuatu dari sesuatu yang dapat dihitung dan diulang.

Jika saya baru saja membuat beberapa urutan bilangan prima yang terbatas, misalnya, urutan bilangan prima yang terbatas ini memang merupakan turunan dari antarmuka System.Collections.IEnumerable, karena sekarang saya dapat membahas semua bilangan prima dalam urutan terbatas ini dalam satu putaran tunggal. dan melakukan apa pun yang ingin saya lakukan dengan masing-masing, seperti mencetak masing-masing ke jendela atau layar konsol, tetapi urutan nomor prima yang terbatas ini bukan turunan dari antarmuka System.Collections.ICollection, karena ini tidak masuk akal untuk tambahkan bilangan komposit ke urutan terbatas bilangan prima ini.

Anda juga ingin dalam iterasi berikutnya untuk mendapatkan bilangan prima terdekat yang lebih besar berikutnya ke bilangan prima saat ini dalam iterasi saat ini, jika demikian Anda juga tidak ingin menghapus bilangan prima yang ada dari urutan bilangan prima yang terbatas ini.

Anda juga mungkin ingin menggunakan, kode, dan tulis "hasil pengembalian" dalam metode GetEnumerator dari System.Collections. Antarmuka yang dapat dihitung untuk menghasilkan bilangan prima dan tidak mengalokasikan apa pun pada tumpukan memori dan kemudian menugaskan Garbage Collector (GC) untuk keduanya deallocate dan bebaskan memori ini dari heap, karena ini jelas membuang-buang memori sistem operasi dan menurunkan kinerja.

Alokasi dan alokasi memori dinamis pada heap harus dilakukan ketika memanggil metode dan properti System.Collections.Collection interface, tetapi tidak ketika memanggil metode dan properti System.Collections.Ini antarmuka yang dapat dihitung (meskipun System.Collections.Ini antarmuka yang dapat dihitung hanya memiliki 1 metode dan 0 properti).

Menurut apa yang dikatakan orang lain di halaman web Stack Overflow ini, antarmuka System.Collections.IList hanya mewakili yang dapat dipesan koleksi yang dapat dan ini menjelaskan mengapa metode System.Collections.Listasis antarmuka bekerja dengan indeks yang berbeda dengan antarmuka System.Collections.ICollection.

Singkatnya antarmuka System.Collections.ICollection tidak menyiratkan bahwa instance itu dapat dipesan, tetapi antarmuka System.Collections.IList tidak menyiratkan itu.

Set yang dipesan secara teoritis adalah case khusus dari unordered set.

Ini juga masuk akal dan menjelaskan mengapa antarmuka System.Collections.IList mewarisi antarmuka System.Collections.ICollection.

pengguna11336341
sumber