Widziałem je używane w ten sam sposób i martwię się, że pójdę ścieżką w projektowaniu, która jest nieodwracalna, jeśli nie zrozumiem tego lepiej. Używam również platformy .NET.
.net
list
collections
Anthony Potts
źródło
źródło
IList
,IList<T>
,List<T>
itd. Krótko mówiąc, nie masz pojęcia, czy zostanie ona wywołana. Polimorfizm rozwiązuje ten problem.ObservableCollection<T>
jako przykład zastąpienie metod powiadamiania o zmianach.W języku C # istnieją trzy koncepcje reprezentowania zbioru obiektów. W kolejności rosnących funkcji są to:
Enumerable nie ma porządku. Nie możesz dodawać ani usuwać elementów z zestawu. Nie możesz nawet policzyć elementów w zestawie. Ściśle umożliwia dostęp do każdego elementu zestawu, jeden po drugim.
Kolekcja to zestaw modyfikowalny. Możesz dodawać i usuwać obiekty z zestawu, możesz też sprawdzić liczbę elementów w zestawie. Ale nadal nie ma porządku, a ponieważ nie ma porządku: nie ma możliwości uzyskania dostępu do elementu według indeksu ani sposobu sortowania.
Lista to uporządkowany zbiór obiektów. Możesz sortować listę, uzyskiwać dostęp do elementów według indeksu, usuwać elementy według indeksu.
W rzeczywistości, patrząc na ich interfejsy, opierają się na sobie:
interface IEnumerable<T>
GetEnumeration<T>
interface ICollection<T> : IEnumerable<T>
Add
Remove
Clear
Count
interface IList<T> = ICollection<T>
Insert
IndexOf
RemoveAt
Deklarując zmienne lub parametry metod, należy wybrać opcję
w oparciu o koncepcję, musisz zrobić z zestawem obiektów.
Jeśli chcesz tylko zrobić coś dla każdego obiektu na liście, potrzebujesz tylko
IEnumerable
:void SaveEveryUser(IEnumerable<User> users) { for User u in users ... }
Nie obchodzi mnie, czy użytkownicy są przechowywane w
List<T>
,Collection<T>
,Array<T>
czy cokolwiek innego. Potrzebujesz tylkoIEnumerable<T>
interfejsu.Jeśli chcesz mieć możliwość dodawania, usuwania lub liczenia elementów w zestawie, użyj kolekcji :
ICollection<User> users = new Collection<User>(); users.Add(new User());
Jeśli zależy Ci na kolejności sortowania i chcesz, aby była ona poprawna, użyj Listy :
IList<User> users = FetchUsers(db);
W formie wykresu:
| 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>
ICollection<T>
naSystem.Collections.Generic
dwie klasy, które implementują te interfejsy; ale to nie jedyne zajęcia:ConcurrentBag<T>
to uporządkowany worek przedmiotów (IEnumerable<T>
)LinkedList<T>
to worek, w którym nie masz dostępu do elementów przez index (ICollection
); ale możesz dowolnie dodawać i usuwać elementy z kolekcjiSynchronizedCollection<T>
w uporządkowanej kolekcji, w której możesz dodawać / usuwać pozycje według indeksuMożesz więc łatwo zmienić:
IEnumerable<User> users = new SynchronizedCollection<User>(); SaveEveryUser(users);
tl; dr
Wybierz potrzebną koncepcję , a następnie użyj pasującej klasy.
źródło
ICollection<T>
iIList<T>
. Różne konkretne implementacje mogą zachowywać się inaczej. Na przykład, jeśli uzyskujesz dostęp do aList<T>
przez jejIEnumerable<T>
interfejs, nie masz możliwości dodawania, usuwania, sortowania ani liczenia elementów na liście.List<T>
jest przeznaczony do użytku wewnętrznego w kodzie aplikacji. Należy unikać pisania publicznych interfejsów API, które akceptują lub zwracająList<T>
(zamiast tego rozważ użycie nadklasy lub interfejsu kolekcji).Collection<T>
obsługuje klasę bazową dla kolekcji niestandardowych (chociaż można jej używać bezpośrednio).Rozważ użycie
Collection<T>
w swoim kodzie, chyba że potrzebujesz określonych funkcjiList<T>
.Powyższe to tylko zalecenia.
[Na podstawie: Wytyczne dotyczące projektowania ram, wydanie drugie]
źródło
Dictionary<string, List<string>>
do powrotuList<string>
jest po prostu w porządku, ponieważ stan słownika za obudowuje jedynie tożsamość wykazów w nim, zamiast ich zawartości.List<T>
jest bardzo często spotykanym kontenerem, ponieważ jest bardzo uniwersalny (z wieloma przydatnymi metodami, takimi jakSort
,Find
itp) - ale nie ma punktów rozszerzenia, jeżeli chcesz nadpisać dowolny zachowania (elementy kontrolne na wkładkę, na przykład).Collection<T>
jest opakowaniem wokół dowolnegoIList<T>
(domyślnieList<T>
) - ma punkty rozszerzeń (virtual
metody), ale nie ma tak wielu metod wsparcia, jakFind
. Z powodu pośredniego kierunku jest nieco wolniejszy niżList<T>
, ale niewiele.Z LINQ, dodatkowe metody w
List<T>
stają się mniej ważne, ponieważ LINQ-Objects dąży do zapewnienia im tak ... na przykładFirst(pred)
,OrderBy(...)
itdźródło
Lista jest szybsza.
Zrób na przykład
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()); }
na moim komputerze
List<>
jest prawie dwa razy szybszy.Edytować
Nie rozumiem, dlaczego ludzie to odrzucają. Zarówno na moim komputerze roboczym, jak i komputerze domowym kod List <> jest o 80% szybszy.
źródło
Lista reprezentuje kolekcję, w której kolejność elementów jest ważna. Obsługuje również metody sortowania i wyszukiwania. Zbieranie jest bardziej ogólną strukturą danych, która przyjmuje mniej założeń dotyczących danych, a także obsługuje mniej metod manipulowania nimi. Jeśli chcesz ujawnić niestandardową strukturę danych, prawdopodobnie powinieneś rozszerzyć kolekcję. Jeśli potrzebujesz manipulować danymi bez ujawniania struktury danych, prawdopodobnie wygodniejszym sposobem jest lista.
źródło
To jedno z tych pytań w szkole średniej. Kolekcja T jest czymś w rodzaju abstrakcji; może istnieć domyślna implementacja (nie jestem facetem .net / c #), ale kolekcja będzie miała podstawowe operacje, takie jak dodawanie, usuwanie, iteracja i tak dalej.
Lista T sugeruje pewne szczegóły dotyczące tych operacji: dodawanie powinno zajmować stały czas, usuwanie powinno zajmować czas proporcjonalny do liczby elementów, getfirst powinno być zgodne z czasem. Ogólnie lista jest rodzajem kolekcji, ale kolekcja niekoniecznie jest rodzajem listy.
źródło
Hanselman Mówi : "
Collection<T>
wygląda jak lista, a nawet maList<T>
wewnętrznie. KAŻDA pojedyncza metoda deleguje do wewnętrznejList<T>
. Zawiera chronioną właściwość, która ujawniaList<T>
."EDYCJA:
Collection<T>
nie istnieje w System.Generic.Collections .NET 3.5. Jeśli przeprowadzasz migrację z .NET 2.0 do 3.5, musisz zmienić kod, jeśli używasz dużoCollection<T>
obiektów, chyba że brakuje mi czegoś oczywistego ...EDYCJA 2:
Collection<T>
jest teraz w przestrzeni nazw System.Collections.ObjectModel w .NET 3.5. Plik pomocy mówi tak:„Przestrzeń nazw System.Collections.ObjectModel zawiera klasy, które mogą być używane jako kolekcje w modelu obiektów biblioteki wielokrotnego użytku. Tych klas należy używać, gdy właściwości lub metody zwracają kolekcje”.
źródło
Wszystkie te interfejsy dziedziczą, z
IEnumerable
których należy się upewnić. Ten interfejs w zasadzie umożliwia użycie klasy w instrukcji foreach (w C #).ICollection
to najbardziej podstawowy z wymienionych interfejsów. Jest to wyliczalny interfejs, który obsługujeCount
i to wszystko.IList
jest wszystkim, coICollection
jest, ale obsługuje także dodawanie i usuwanie elementów, pobieranie elementów według indeksu, itp. Jest to najczęściej używany interfejs dla „list obiektów”, który jest niejasny, jaki znam.IQueryable
jest wyliczalnym interfejsem obsługującym LINQ. Zawsze możesz utworzyćIQueryable
z IList i użyć LINQ to Objects, ale możesz również znaleźćIQueryable
używane do odroczonego wykonywania instrukcji SQL w LINQ to SQL i LINQ to Entities.IDictionary
jest innym zwierzęciem w tym sensie, że jest odwzorowaniem unikalnych kluczy na wartości. Jest również wyliczalny, ponieważ możesz wyliczyć pary klucz / wartość, ale poza tym służy innym celom niż inne wymienione przez Ciebieźródło
Według MSDN List (Of T) .Add to „operacja O (n)” (gdy „Capacity” jest przekroczona), podczas gdy Collection (Of T) .Add jest zawsze „operacją O (1)”. Byłoby to zrozumiałe, gdyby lista została zaimplementowana przy użyciu tablicy, a kolekcja - lista połączona. Jednak gdyby tak było, należałoby oczekiwać, że Collection (Of T) .Item będzie „operacją O (n)”. Ale - to - nie !?! Collection (Of T) .Item jest „operacją O (1)”, podobnie jak List (Of T) .Item.
Co więcej, powyższy post „tuinstoel” z 29 grudnia 2008 o 22:31 twierdzi, że testy prędkości pokazują List (Of T) .Dodaj, aby być szybszym niż Collection (Of T). Dodaj, który odtworzyłem z Długie i Stringi. Chociaż osiągnąłem tylko ~ 33% szybciej niż jego deklarowane 80%, według MSDN powinno być odwrotnie i o „n” razy!?!
źródło
Oba implementują te same interfejsy, więc będą się zachowywać w ten sam sposób. Być może są one wdrażane wewnętrznie inaczej, ale należałoby to przetestować.
Jedyne rzeczywiste różnice, które widzę, to przestrzenie nazw i fakt, że
Collection<T>
jest oznaczonyComVisibleAttribute(false)
, więc kod COM nie może go używać.źródło
Oprócz innych odpowiedzi, opracowałem szybki przegląd ogólnych możliwości list i kolekcji. Kolekcja jest ograniczonym podzbiorem Listy:
* = obecny o = częściowo obecny Property / Method Collection <T> List <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() *
źródło