Liste (of T) ve Collection (of T) arasındaki fark nedir?


96

Bunların birçok aynı şekilde kullanıldığını gördüm ve daha iyi anlamazsam tasarımda geri dönüşü olmayan bir yola girmek üzereyim diye endişeleniyorum. Ayrıca .NET kullanıyorum.

Yanıtlar:


50

Collection<T>etrafında özelleştirilebilir bir sarmalayıcıdır IList<T>. IList<T>Mühürlü olmamakla birlikte , herhangi bir özelleştirme noktası sağlamaz. Collection<T>'ın yöntemleri varsayılan olarak standart IList<T>yöntemlere atanır, ancak istediğinizi yapmak için kolayca geçersiz kılınabilir. Ayrıca Collection<T>bir IList ile yapılabileceğine inanmadığım olayları telaklamak da mümkündür .

Kısacası, gerçeğin ardından genişletmek çok daha kolaydır, bu da potansiyel olarak çok daha az yeniden düzenleme anlamına gelebilir.


@Marc Gravell, @Adam Lassek: InsertItem (...) yöntemini public void new InsertItem (...) ile gizleyip sonra base.InsertItem (.. .) içinden ? Yine de sözleşmeyi bozmaz. (isim Listedeki 'Ekle'dir, ancak yine de). Peki, Koleksiyonlara bağlı kalmanın en önemli yanı nedir <T>?
DeeStackOverflow

4
@DeeStackOverflow - için görünümün onun yani şey - yöntemi gizleme farklı bir API kullanan herhangi kod tarafından kullanılamaz çünkü IList, IList<T>, List<T>vb Kısacası, bunu adı verilecek olup hiçbir fikrim yok. Çok biçimlilik bunu düzeltir.
Marc Gravell

1
@AdamLassek: Cevabınıza ObservableCollection<T>, değişiklikleri bildirmek için yöntemlerin geçersiz kılındığı bir örnek olarak eklemek isteyebilirsiniz .
Kiran Challa

92

C # 'da, bir nesne çantasını temsil etmek için üç kavram vardır. Artan özellik sırasına göre bunlar:

  • Numaralandırılabilir - sırasız, değiştirilemez
  • Koleksiyon - öğe ekleyebilir / kaldırabilir
  • Liste - öğelerin bir sıraya sahip olmasına izin verir (dizine göre erişim ve kaldırma)

Numaralandırılmanın sırası yoktur. Setten öğe ekleyemez veya kaldıramazsınız. Sette bir dizi öğe bile alamazsınız. Setteki her bir öğeye birbiri ardına erişmenize kesinlikle izin verir.

Koleksiyon değiştirilebilir bir settir. Setten nesneler ekleyebilir ve kaldırabilirsiniz, ayrıca setteki öğelerin sayısını da alabilirsiniz. Ama hala bir düzen yok ve bir düzen olmadığı için: bir öğeye indekse göre erişmenin bir yolu veya sıralamanın herhangi bir yolu yok.

Liste , sıralı bir nesne kümesidir. Listeyi sıralayabilir, öğelere indekse göre erişebilir, öğeleri indekse göre kaldırabilirsiniz.

Aslında, bunların arayüzlerine bakıldığında, birbirlerinin üzerine inşa ederler:

  • interface IEnumerable<T>

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

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

    • Insert
    • IndexOf
    • RemoveAt

Değişkenleri veya yöntem parametrelerini bildirirken, kullanmayı seçmelisiniz

  • IEnumerable
  • ICollection
  • IList

kavramsal olarak, nesneler kümesiyle yapmanız gereken temel alır.

Listedeki her nesneye bir şeyler yapabilmeniz gerekiyorsa, o zaman yalnızca şunlara ihtiyacınız vardır IEnumerable:

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

Kullanıcılar tutulur eğer umurumda değil List<T>, Collection<T>, Array<T>başka ya da bir şey. Sadece IEnumerable<T>arayüze ihtiyacınız var .

Bir kümedeki öğeleri eklemeniz, kaldırmanız veya saymanız gerekiyorsa, bir Koleksiyon kullanın :

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

Bir sıralama düzenini önemsiyorsanız ve sıranın doğru olmasını istiyorsanız, bir Liste kullanın :

IList<User> users = FetchUsers(db);

Grafik biçiminde:

| 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        |

List<T>Ve Collection<T>de System.Collections.Genericbu arabirimleri uygulayan iki sınıf vardır; ancak bunlar tek sınıf değil:

  • ConcurrentBag<T>sıralı bir nesne torbasıdır ( IEnumerable<T>)
  • LinkedList<T>indeks ( ICollection) ile öğelere erişmenize izin verilmeyen bir çantadır ; ancak keyfi olarak koleksiyona öğe ekleyebilir ve koleksiyondan öğe kaldırabilirsiniz
  • SynchronizedCollection<T> dizine göre öğe ekleyebileceğiniz / kaldırabileceğiniz sıralı bir koleksiyonda

Böylece aşağıdakileri kolayca değiştirebilirsiniz:

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

SaveEveryUser(users);

tl; dr

  • Numaralandırılabilir - erişim öğeleri, sırasız, değiştirilemez
  • Koleksiyon - değiştirilebilir (ekleme, silme, sayma)
  • Liste - dizine göre erişebilir

İhtiyacınız olan kavramı seçin , ardından uygun sınıfı kullanın.


11
OP somut türleri sordu ve siz Arabirimleri karşılaştırdınız. Somut Collection <T> türü IList <T> uygular ve indeks yeteneklerine göre erişime sahiptir.
JJS

2
Cevap iyi ama sorudan sapmış. <T> Koleksiyonu ve Liste <T> sınıfları için cevabınız uymuyor, yani olası sorudan demek istediğim, amacınızı doğrulamaya çalışırsam, haklı çıkarmazlar. Genel amaçlı bir cevap için, koleksiyonun sıralanmadığı için indeksleme yapılmadığı konusunda haklı olabilirsiniz, ancak liste sıralanır, böylece belirli bir indekste ekleme mümkün olur.
Kylo Ren

Ya ICollection <T> 'den gelen özelliklere sahip olursam ve ayrıca çözme ve olasılık bulursam?

2
Liste sıralıysa ve koleksiyon düzenliyse, bu yeni bir öğrencinin (benim gibi) seçim yapmasına kolayca rehberlik etmek için büyük bir işlevsel fark olacaktır. Ama bekle, neden koleksiyonun siparişi olmadığını söylüyorsun? Sağladığı IndexOf () ve RemoveAt () o, o sipariş IS yüzden yöntem değil? Burada bir şey mi özledim?
RayLuo

1
@RayLuo Ben özellikle ICollection<T>ve IList<T>. Farklı somut uygulamalar farklı davranabilir. Örneğin List<T>, bir IEnumerable<T>arayüzüne erişirseniz , listedeki öğeleri eklemeniz, kaldırmanız, sıralamanız veya saymanız mümkün değildir.
Ian Boyd

44

List<T>uygulama kodu içerisinde dahili kullanım için tasarlanmıştır. Kabul eden veya dönen genel API'ler yazmaktan kaçınmalısınız List<T>(bunun yerine bir üst sınıf veya bir koleksiyon arabirimi kullanmayı düşünün).

Collection<T> özel koleksiyonlar için temel bir sınıf sunar (ancak doğrudan da kullanılabilir).

İhtiyaç duyduğunuz Collection<T>belirli özellikler yoksa kodunuzda kullanmayı düşünün List<T>.

Yukarıdakiler sadece önerilerdir.

[Framework Design Guidelines, Second Edition'dan uyarlanmıştır]


Kendi durumlarını kapsüllemek için herhangi bir tür değiştirilebilir nesneyi kullanan türlerin, söz konusu nesneler değiştirildiklerinde sahiplerine bildirimde bulunma araçlarına sahip olmadıkça veya nesne açıkça yeni bir örnek döndürdüğünü ima eder. Sözlüğün durumu , içeriklerinden ziyade sadece buradaki listelerin kimliklerini kapsadığından, örneğin a'nın geri dönüşünün gayet iyi olduğuna dikkat edin. Dictionary<string, List<string>>List<string>
supercat

37

List<T>o (gibi kullanışlı yöntemlerle bir sürü ile çok yönlü böyledir, çünkü çok sık görülen bir kapsayıcı olmadığından Sort, Findancak herhangi bir davranış geçersiz kılmak istiyorsanız (uç üzerindeki onay öğeleri örneğin) uzatma noktaları vardır -, vs).

Collection<T>herhangi birinin etrafında bir sarmalayıcıdır IList<T>(varsayılan olarak List<T>) - uzantı noktalarına ( virtualyöntemlerine) sahiptir, ancak Find. Dolaylı yoldan dolayı, biraz daha yavaştır List<T>, ama fazla değil.

LINQ ile ekstra yöntemler List<T>beri daha az önemli hale Neyse bunları sağlamak eğilimindedir-to-Nesneler LINQ ... örneğin First(pred), OrderBy(...)vb


6
Koleksiyon <T>, Linq-to-Objects'te bile foreach yönteminden yoksundur.
tuinstoel

7
@tuinstoel - ancak eklenmesi önemsizdir.
Marc Gravell

12

Liste daha hızlı.

Örneğin yap

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());


}

makinemde List<>neredeyse iki kat daha hızlı.

Düzenle

İnsanların buna neden olumsuz oy verdiğini anlayamıyorum. Hem iş makinemde hem de ev makinemde Liste <> kodu% 80 daha hızlı.


1
Nasıl daha hızlı? Yukarı Bak? Yerleştirme? Kaldırma mı? Arama? Neden daha hızlı?
Doug T.

17
Liste, Koleksiyondan daha az harf
içeriyor

1
Koleksiyonun daha az yöntemi vardır. Bu nedenle daha hızlıdır. QED. (şaka yapmıyorum)
Ray

2
Makinemde denedim ve liste yaklaşık% 20 daha hızlı. Bunun neden olabileceğine dair bazı tartışmalarla ilgilenirim. Belki liste bellek ayırmada daha iyidir.
Ray

10
List'in yöntemleri miras alınamaz, bu nedenle miras alınıp alınmadıklarını görmek için kontroller yoktur; Koleksiyonun yöntemleri miras alınabilir. Bunun avantajı, Koleksiyonu özel bir Koleksiyondan miras almak ve oluşturmak için temel sınıf olarak kullanabilmenizdir.
Richard Gadsden

11

Liste, öğelerin sırasının önemli olduğu bir koleksiyonu temsil eder. Ayrıca, sıralama ve arama yöntemlerini de destekler. Toplama, veriler hakkında daha az varsayımda bulunan ve aynı zamanda verileri işlemek için daha az yöntemi destekleyen daha genel bir veri yapısıdır. Özel bir veri yapısını ortaya çıkarmak istiyorsanız, muhtemelen koleksiyonu genişletmelisiniz. Veri yapısını açığa çıkarmadan verileri değiştirmeniz gerekirse, bir liste muhtemelen gitmenin daha uygun yoludur.


4

Bu şu yüksek okul sorularından biri. Bir T Koleksiyonu bir tür soyuttur; varsayılan bir uygulama olabilir (ben bir .net / c # adamı değilim) ancak bir koleksiyon ekleme, kaldırma, yineleme vb. gibi temel işlemlere sahip olacaktır.

T listesi, bu işlemlerle ilgili bazı özellikleri ima eder: toplama işlemi sabit zaman almalı, kaldırma süresi öğelerin sayısı ile orantılı olmalı, ilk önce sabit zaman olmalıdır. Genelde Liste bir Koleksiyon türüdür, ancak Koleksiyon mutlaka bir tür Liste değildir.


4

Hanselman şöyle konuşuyor : " Collection<T>Bir liste gibi görünüyor ve hatta List<T>dahili olarak bir tane var. HER tek yöntem dahili olarak delege ediyor List<T>. Bu, ortaya çıkaran korumalı bir özelliği içeriyor List<T>."

DÜZENLEME: Collection<T>System.Generic.Collections .NET 3.5'te mevcut değil. NET 2.0'dan 3.5'e geçiş yaparsanız Collection<T>, bariz bir şeyi kaçırmadığım sürece, çok sayıda nesne kullanıyorsanız bazı kodları değiştirmeniz gerekecektir ...

DÜZENLEME 2: Collection<T>artık .NET 3.5'te System.Collections.ObjectModel ad alanında. Yardım dosyası şunu söylüyor:

"System.Collections.ObjectModel ad alanı, yeniden kullanılabilir bir kitaplığın nesne modelinde koleksiyonlar olarak kullanılabilen sınıfları içerir. Özellikler veya yöntemler koleksiyonları döndürdüğünde bu sınıfları kullanın."


4

Tüm bu arayüzler IEnumerable, anladığınızdan emin olmanız gereken kaynaklardan miras alınır . Bu arayüz temelde sınıfı bir foreach ifadesinde (C # 'da) kullanmanıza izin verir.

  • ICollectionlistelediğiniz arayüzlerin en temelidir. A'yı destekleyen numaralandırılabilir bir arayüz Countve bununla ilgili.
  • IListolan her şeydir ICollection, ancak aynı zamanda öğe ekleme ve kaldırma, indekse göre öğe alma, vb. destekler. Bildiğim belirsiz "nesne listeleri" için en yaygın kullanılan arabirimdir.
  • IQueryableLINQ destekleyen bir numaralandırılabilir arabirimdir. Her zaman IQueryablebir IList'ten bir IList oluşturabilir ve LINQ to Objects'i kullanabilirsiniz, ancak ayrıca IQueryableLINQ to SQL ve LINQ to Entities'de SQL ifadelerinin ertelenmiş yürütmesi için kullanıldığını da bulabilirsiniz .
  • IDictionarydeğerlere benzersiz anahtarların bir eşlemesi olması açısından farklı bir hayvandır. Anahtar / değer çiftlerini sıralayabileceğiniz için de numaralandırılabilir, ancak aksi takdirde listelediğiniz diğerlerinden farklı bir amaca hizmet eder.

ICollection ekleme / kaldırma / temizlemeyi destekler: msdn.microsoft.com/en-us/library/…
amnezi

4

MSDN'ye göre, List (Of T) .Add "bir O (n) işlemi" dir ("Kapasite" aşıldığında), Toplama (Of T) .Add ise her zaman "bir O (1) işlemi" dir. List, bir Dizi ve Koleksiyon bir Bağlantılı Liste kullanılarak uygulanırsa bu anlaşılabilir bir durumdur. Ancak, durum böyle olsaydı, Collection (Of T) .Item'in "bir O (n) işlemi" olması beklenirdi. Ama - bu - değil !?! Collection (Of T) .Item, List (Of T) gibi "bir O (1) işlemi" dir.

Bunun da ötesinde, "tuinstoel" 'in "29 Aralık '08, 22:31" gönderisi, hız testleri Listesini (Of T) gösteriyor. Koleksiyondan (Of T) daha hızlı olması için ekle. Long ve String'ler. Onun talep edilen% 80'ine kıyasla sadece ~% 33 daha hızlı olmama rağmen, MSDN'ye göre bunun tam tersi ve "n" kez olmalıydı!?!


3

Her ikisi de aynı arayüzleri uygular, böylece aynı şekilde davranırlar. Belki dahili olarak farklı şekilde uygulanırlar, ancak bunun test edilmesi gerekir.

Gördüğüm tek gerçek fark, ad alanları ve Collection<T>ile işaretlenmiş olmaları ComVisibleAttribute(false), dolayısıyla COM kodu onu kullanamaz.


Farklı arabirimler uygularlar - List <T> IList <T> uygular, burada Collection <T> bunu yapmaz.
Bevan

C # denemek @Bevan, ikisi de arayüzleri aynı kümesini uygulamak
Kylo Ren'i

1
Bu ilginç bir değişim @KyloRen var - onlar do artık iki arayüzde aynı set uygulamak; 2008'deki durum böyle değildi.
Bevan

1
@Bevan ilginç. İki farklı sınıfın sebebinin ne olduğundan emin değilim, biri sadece ekstra yöntemlerle.
Kylo Ren

3

Diğer sorulara ek olarak, genel liste ve koleksiyon yeteneklerine hızlı bir genel bakış derledim. Koleksiyon, Listenin sınırlı bir alt kümesidir:

* = mevcut
o = kısmen mevcut

Özellik / Yöntem Koleksiyon <T> Listesi <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()                        *
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.