Apa perbedaan antara List (of T) dan Collection (of T)?

93

Saya telah melihat mereka digunakan dengan banyak cara yang sama, dan saya khawatir saya akan menempuh jalur dalam desain yang tidak dapat diubah jika saya tidak memahami ini dengan lebih baik. Juga, saya menggunakan .NET.

Anthony Potts
sumber

Jawaban:

50

Collection<T>adalah pembungkus yang dapat disesuaikan IList<T>. Meskipun IList<T>tidak disegel, itu tidak memberikan poin kustomisasi apa pun. Collection<T>Metode secara default didelegasikan ke IList<T>metode standar , tetapi dapat dengan mudah diganti untuk melakukan apa yang Anda inginkan. Dimungkinkan juga untuk memasang acara di dalam Collection<T>yang saya tidak percaya dapat dilakukan dengan IList.

Singkatnya, jauh lebih mudah untuk memperpanjangnya setelah terjadi, yang berpotensi berarti jauh lebih sedikit refactoring.

Adam Lassek
sumber
@Marc Gravell, @Adam Lassek: Tidak bisakah kita melakukan hal yang sama dengan List dengan menyembunyikan metode InsertItem (...) dengan InsertItem baru (...) public void dan kemudian memanggil base.InsertItem (.. .) dari dalam ? Itu tetap tidak akan memutuskan kontrak. (namanya adalah 'Sisipkan' dalam Daftar, tapi tetap saja). Jadi apa masalahnya jika tetap menggunakan Koleksi <T>?
DeeStackOverflow
4
@DeeStackOverflow - karena metode bersembunyi tidak akan digunakan oleh kode yang menggunakan API yang berbeda - yaitu Apa pun yang terlihat untuk IList, IList<T>, List<T>dll Singkatnya, Anda tidak tahu apakah itu akan disebut. Polimorfisme memperbaiki ini.
Marc Gravell
@AdamLassek: Anda mungkin ingin menambahkan jawaban Anda tentang ObservableCollection<T>sebagai contoh di mana metode diganti untuk memberi tahu tentang perubahan.
Kiran Challa
84

Di C #, ada tiga konsep untuk merepresentasikan sekantong benda. Untuk meningkatkan fitur, mereka adalah:

  • Enumerable - unordered, unmodifiable
  • Koleksi - dapat menambah / menghapus item
  • Daftar - memungkinkan item memiliki pesanan (mengakses dan menghapus dengan indeks)

Enumerable tidak memiliki urutan. Anda tidak dapat menambah atau menghapus item dari set. Anda bahkan tidak bisa mendapatkan hitungan item di set. Ini secara ketat memungkinkan Anda mengakses setiap item dalam set, satu demi satu.

Koleksi adalah satu set yang dapat dimodifikasi. Anda dapat menambah dan menghapus objek dari himpunan, Anda juga bisa mendapatkan jumlah item dalam himpunan. Tetapi masih belum ada urutan, dan karena tidak ada urutan: tidak ada cara untuk mengakses item dengan indeks, juga tidak ada cara untuk mengurutkan.

Daftar adalah sekumpulan objek yang diurutkan. Anda dapat mengurutkan daftar, mengakses item berdasarkan indeks, menghapus item berdasarkan indeks.

Faktanya, ketika melihat antarmuka untuk ini, mereka membangun satu sama lain:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

Saat mendeklarasikan variabel, atau parameter metode, Anda harus memilih untuk menggunakan

  • IEnumerable
  • ICollection
  • IList

berdasarkan konseptual yang perlu Anda lakukan dengan himpunan objek.

Jika Anda hanya perlu melakukan sesuatu untuk setiap objek dalam daftar, Anda hanya perlu IEnumerable:

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

Anda tidak peduli jika Pengguna disimpan dalam List<T>, Collection<T>, Array<T>atau apa pun. Anda hanya membutuhkanIEnumerable<T> antarmuka.

Jika Anda ingin dapat menambah, menghapus, atau menghitung item dalam satu set, gunakan Koleksi :

ICollection<User> users = new Collection<User>();
users.Add(new User());

Jika Anda peduli dengan tata urutan, dan ingin urutannya benar, gunakan Daftar :

IList<User> users = FetchUsers(db);

Dalam bentuk grafik:

| Feature                | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items      | X              | X              | X        |
|                        |                |                |          |
| Adding items           |                | X              | X        |
| Removing items         |                | X              | X        |
| Count of items         |                | X              | X        |
|                        |                |                |          |
| Accessing by index     |                |                | X        |
| Removing by indexx     |                |                | X        |
| Getting index of item  |                |                | X        |

The List<T>dan Collection<T>in System.Collections.Genericadalah dua kelas yang mengimplementasikan antarmuka ini; tetapi mereka bukan satu-satunya kelas:

  • ConcurrentBag<T>adalah tas benda yang dipesan ( IEnumerable<T>)
  • LinkedList<T>adalah tas di mana Anda tidak diizinkan untuk mengakses item menurut index ( ICollection); tetapi Anda dapat menambahkan dan menghapus item dari koleksi secara sewenang-wenang
  • SynchronizedCollection<T> dalam koleksi terurut, di mana Anda dapat menambah / menghapus item berdasarkan indeks

Jadi, Anda dapat dengan mudah mengubah:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

tl; dr

  • Enumerable - item akses, tidak berurutan, tidak dapat dimodifikasi
  • Koleksi - dapat dimodifikasi (tambah, hapus, hitung)
  • Daftar - dapat diakses berdasarkan indeks

Pilih konsep yang Anda butuhkan, kemudian gunakan kelas yang sesuai.

Ian Boyd
sumber
11
OP bertanya tentang jenis beton, dan Anda telah membandingkan Antarmuka. Collection tipe konkret <T> mengimplementasikan IList <T> dan memiliki kemampuan pengaksesan indeks.
JJS
2
Jawabannya bagus tapi melenceng dari soal. Tidak bisa sesuai dengan jawaban Anda untuk kelas Collection <T> dan List <T>, maksud saya dari pertanyaan prospektif jika saya mencoba untuk memvalidasi poin Anda mereka hanya tidak membenarkan. Untuk jawaban tujuan umum Anda mungkin benar bahwa koleksi tidak diurutkan sehingga tidak ada pengindeksan, tetapi daftar diurutkan sehingga penyisipan dimungkinkan pada indeks tertentu.
Kylo Ren
bagaimana jika saya ingin memiliki fitur dari ICollection <T> dan juga solrting dan menemukan kemungkinan?
2
Jika daftarnya diurutkan dan koleksinya tidak berurutan, itu akan menjadi perbedaan fungsional yang sangat besar untuk memandu pelajar baru (seperti saya) untuk memilih dengan mudah. Tapi tunggu dulu, mengapa Anda mengatakan koleksi tidak ada pesanan? Ini menyediakan metode IndexOf () dan RemoveAt () , jadi IS dipesan, bukan? Apakah saya melewatkan sesuatu di sini?
RayLuo
1
@RayLuo yang saya maksudkan secara khusus ICollection<T>dan IList<T>. Implementasi konkret yang berbeda mungkin berperilaku berbeda. Misalnya jika Anda mengakses a List<T>melalui IEnumerable<T>antarmukanya, maka Anda tidak memiliki cara untuk menambah, menghapus, menyortir, atau menghitung item dalam daftar.
Ian Boyd
43

List<T>ditujukan untuk penggunaan internal dalam kode aplikasi. Anda harus menghindari menulis API publik yang menerima atau mengembalikan List<T>(pertimbangkan untuk menggunakan superclass atau antarmuka koleksi sebagai gantinya).

Collection<T> menyajikan kelas dasar untuk koleksi khusus (meskipun dapat digunakan secara langsung).

Pertimbangkan untuk menggunakan Collection<T>dalam kode Anda kecuali ada fitur khusus dariList<T> yang Anda butuhkan.

Di atas hanyalah rekomendasi.

[Diadaptasi dari: Panduan Desain Kerangka, Edisi Kedua]

Arnold Zokas
sumber
Perlu dicatat bahwa tipe yang menggunakan segala jenis objek yang bisa berubah untuk merangkum statusnya sendiri harus menghindari mengembalikan objek dengan tipe seperti itu kecuali objek yang dimaksud memiliki sarana untuk memberi tahu pemiliknya saat dimutasi, atau nama metode yang mengembalikan objek secara jelas menyiratkan bahwa ia mengembalikan instance baru. Perhatikan bahwa misalnya Dictionary<string, List<string>>untuk mengembalikan List<string>tidak apa-apa, karena status kamus hanya merangkum identitas daftar di dalamnya, bukan isinya.
supercat
37

List<T>adalah wadah yang sangat umum dilihat, karena sangat serbaguna (dengan banyak metode praktis seperti Sort,, Finddll) - tetapi tidak memiliki titik ekstensi jika Anda ingin menimpa perilaku apa pun (centang item saat menyisipkan, misalnya).

Collection<T>adalah pembungkus di sekitar IList<T>(default ke List<T>) - ia memiliki titik ekstensi ( virtualmetode), tetapi tidak banyak metode dukungan seperti Find. Karena tipuan, ini sedikit lebih lambat dariList<T> , tetapi tidak terlalu banyak.

Dengan LINQ, metode ekstra dalam List<T>menjadi kurang penting, karena LINQ-to-Objek cenderung untuk memberikan mereka pula ... misalnya First(pred), OrderBy(...), dll

Marc Gravell
sumber
6
Koleksi <T> tidak memiliki metode untuk setiap, bahkan di Lini-ke-Objek.
tuinstoel
7
@tuinstoel - tapi itu sepele untuk ditambahkan.
Marc Gravell
12

Daftar lebih cepat.

Lakukan misalnya

private void button1_Click(object sender, EventArgs e)
{
  Collection<long> c = new Collection<long>();
  Stopwatch s = new Stopwatch();
  s.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    c.Add(i);
  }
  s.Stop();
  MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());

  List<long> l = new List<long>();
  Stopwatch s2 = new Stopwatch();
  s2.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    l.Add(i);
  }
  s2.Stop();
  MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());


}

di mesin saya List<>hampir dua kali lebih cepat.

Edit

Saya tidak mengerti mengapa orang-orang tidak menyukai ini. Baik di mesin kerja saya dan mesin rumah saya, kode Daftar <> 80% lebih cepat.

tuinstoel
sumber
1
Bagaimana lebih cepat? Menengadah? Insersi? Pemindahan? Cari? Kenapa lebih cepat?
Doug T.
17
Daftar lebih sedikit huruf untuk
diketik
1
Koleksi memiliki lebih sedikit metode. Karena itu lebih cepat. QED. (bercanda, saya tidak mengolok-olok)
Ray
2
Sudah mencobanya di komputer saya dan daftarnya sekitar 20% lebih cepat. Akan tertarik dengan beberapa diskusi tentang mengapa ini mungkin terjadi. Mungkin daftarnya lebih baik dengan mengalokasikan memori.
Ray
10
Metode List tidak dapat diwariskan sehingga tidak ada pemeriksaan untuk melihat apakah mereka telah diwarisi; Metode koleksi dapat diwariskan. Keuntungannya adalah Anda dapat menggunakan Collection sebagai kelas dasar untuk mewarisi dan membuat Collection kustom.
Richard Gadsden
11

List merepresentasikan koleksi yang urutan itemnya penting. Ini juga mendukung metode Sortir dan pencarian. Koleksi adalah struktur data yang lebih umum yang membuat lebih sedikit asumsi tentang data dan juga mendukung lebih sedikit metode untuk memanipulasinya. Jika Anda ingin mengekspos struktur data kustom, Anda mungkin harus memperluas koleksi. Jika Anda perlu memanipulasi data tanpa mengekspos struktur data, daftar mungkin adalah cara yang lebih nyaman untuk digunakan.

Manu
sumber
4

Ini adalah salah satu pertanyaan sekolah pascasarjana. Koleksi T adalah semacam abstrak; mungkin ada implementasi default (saya bukan orang .net / c #) tetapi koleksi akan memiliki operasi dasar seperti menambah, menghapus, mengulang, dan sebagainya.

Daftar T menyiratkan beberapa hal spesifik tentang operasi ini: menambahkan harus mengambil waktu yang konstan, menghapus harus mengambil waktu sebanding dengan jumlah elemen, getfirst harus waktu yang sama. Secara umum, Daftar adalah sejenis Koleksi, tetapi Koleksi belum tentu merupakan jenis Daftar.

Charlie Martin
sumber
4

Hanselman Speaks : " Collection<T>terlihat seperti daftar, dan bahkan memiliki List<T>internal. SETIAP metode tunggal didelegasikan ke internal List<T>. Ini termasuk properti terlindungi yang mengekspos List<T>."

EDIT: Collection<T>tidak ada di System.Generic.Collections .NET 3.5. Jika Anda bermigrasi dari .NET 2.0 ke 3.5 Anda perlu mengubah beberapa kode jika Anda menggunakan banyakCollection<T> objek, kecuali saya kehilangan sesuatu yang jelas ...

EDIT 2: Collection<T>sekarang dalam namespace System.Collections.ObjectModel di .NET 3.5. File bantuan mengatakan ini:

"Ruang nama System.Collections.ObjectModel berisi kelas yang dapat digunakan sebagai koleksi dalam model objek perpustakaan yang dapat digunakan kembali. Gunakan kelas ini saat properti atau metode mengembalikan koleksi."

Tad Donaghe
sumber
4

Semua antarmuka ini diwarisi IEnumerable, yang harus Anda pastikan Anda mengerti. Antarmuka itu pada dasarnya memungkinkan Anda menggunakan kelas dalam pernyataan foreach (dalam C #).

  • ICollectionadalah antarmuka paling dasar yang Anda daftarkan. Ini adalah antarmuka yang tak terhitung banyaknya yang mendukung Countdan hanya itu.
  • IListadalah segalanya ICollection, tetapi juga mendukung penambahan dan penghapusan item, mengambil item berdasarkan indeks, dll. Ini adalah antarmuka yang paling umum digunakan untuk "daftar objek", yang saya tahu tidak jelas.
  • IQueryableadalah antarmuka yang dapat dihitung yang mendukung LINQ. Anda selalu dapat membuat IQueryabledari IList dan menggunakan LINQ ke Objek, tetapi Anda juga dapat menemukan IQueryabledigunakan untuk eksekusi pernyataan SQL yang ditangguhkan di LINQ ke SQL dan LINQ ke Entitas.
  • IDictionaryadalah hewan yang berbeda dalam arti bahwa ini adalah pemetaan kunci unik untuk nilai. Ini juga dapat dihitung sehingga Anda dapat menghitung pasangan kunci / nilai, tetapi selain itu melayani tujuan yang berbeda dari yang lain yang Anda cantumkan
Raj Gupta
sumber
ICollection mendukung penambahan / penghapusan / pembersihan: msdn.microsoft.com/en-us/library/…
amnesia
4

Menurut MSDN, List (Of T) .Add adalah "operasi O (n)" (ketika "Kapasitas" terlampaui) sedangkan Collection (Of T) .Add selalu "operasi O (1)". Itu akan bisa dimengerti jika List diimplementasikan menggunakan Array dan Collection a Linked List. Namun, jika itu masalahnya, orang akan mengharapkan Collection (Of T) .Item menjadi "operasi O (n)". Tapi - ini - tidak !?! Collection (Of T) .Item adalah "operasi O (1)" seperti List (Of T) .Item.

Selain itu, "tuinstoel "'s" Dec 29 '08 at 22:31 "posting di atas mengklaim tes kecepatan menunjukkan Daftar (Dari T). Tambahkan menjadi lebih cepat daripada Koleksi (Dari T). Tambahkan yang telah saya reproduksi dengan Panjang dan String. Meskipun saya hanya mendapatkan ~ 33% lebih cepat vs. klaimnya 80%, menurut MSDN, seharusnya sebaliknya dan dengan "n" kali!?!

Tom
sumber
3

Keduanya menerapkan antarmuka yang sama, jadi mereka akan berperilaku dengan cara yang sama. Mungkin mereka diterapkan secara berbeda secara internal, tetapi ini harus diuji.

Satu-satunya perbedaan nyata yang saya lihat adalah ruang nama dan fakta yang Collection<T>ditandai dengan ComVisibleAttribute(false), jadi kode COM tidak dapat menggunakannya.

OwenP
sumber
Mereka mengimplementasikan antarmuka yang berbeda - List <T> mengimplementasikan IList <T>, di mana Collection <T> tidak.
Bevan
@Bevan mencobanya di c #, mereka berdua menerapkan seperangkat antarmuka yang sama
Kylo Ren
1
Itu merupakan @KyloRen perubahan yang menarik - mereka lakukan sekarang kedua menerapkan set yang sama interface; ini tidak terjadi di tahun '08.
Bevan
1
@Bevan menarik. Tidak yakin apa alasan dari dua kelas yang berbeda, satu hanya dengan beberapa metode tambahan.
Kylo Ren
3

Selain jawaban lain, saya telah menyusun ikhtisar singkat tentang daftar umum dan kemampuan pengumpulan. Koleksi adalah bagian terbatas dari Daftar:

* =  sekarang
o = hadir sebagian

Pengumpulan Properti / Metode < T > Daftar < T > --------------------------------------- -------      

Add()                *              *
AddRange()                          *
AsReadOnly()                        *
BinarySearch()                      *
Capacity                            *
Clear()              *              *
Contains()           *              *
ConvertAll()                        *
CopyTo()             o              *
Count                *              *
Equals()             *              *
Exists()                            *
Find()                              *
FindAll()                           *
FindIndex()                         *
FindLast()                          *
FindLastIndex()                     *
ForEach()                           *
GetEnumerator()      *              *
GetHashCode()        *              *
GetRange()                          *
GetType()            *              *
IndexOf()            o              *
Insert()             *              *
InsertRange()                       *
Item()               *              *
LastIndexOf()                       *
New()                o              *
ReferenceEquals()    *              *
Remove()             *              *
RemoveAll()                         *
RemoveAt()           *              *
RemoveRange()                       *
Reverse()                           *
Sort()                              *
ToArray()                           *
ToString()           *              *
TrimExcess()                        *
TrueForAll()                        *
miroxlav.dll
sumber