Tak, właściwie. List<T>jest klasą ogólną. Obsługuje przechowywanie wartości określonego typu bez rzutowania do lub z object(co spowodowałoby obciążenie związane z boksem / rozpakowaniem, gdy Tjest to typ wartości w ArrayListprzypadku). ArrayListpo prostu przechowuje objectreferencje. Jako zbiór rodzajową List<T>realizuje ogólne IEnumerable<T>interfejs i mogą być łatwo stosowane w LINQ (bez potrzeby dokonywania jakiejkolwiek Castlub OfTypepołączenia).
ArrayListnależy do dni, w których C # nie miał generycznych. Jest przestarzałe na korzyść List<T>. Nie powinieneś używać ArrayListw nowym kodzie kierowanym na .NET> = 2.0, chyba że musisz połączyć się ze starym API, który go używa.
Czy mógłbyś wyjaśnić, dlaczego używałeś „boksu”, a nie „castingu”? Co się tutaj dzieje? Czy obiekty są przydzielane / zwalniane?
Benjamin Gruenbaum,
2
@BenjaminGruenbaum Masz rację, że casting byłby bardziej ogólny. To powiedziawszy, prawdziwa różnica w środowisku wykonawczym polega na tym, że masz do czynienia z typami wartości (co założyłem, gdy napisałem „boks”). W przypadku typów referencyjnych zachowanie jest faktycznie takie samo jak ArrayListw środowisku wykonawczym. Statycznie będzie to wymagało obsady za pomocą ArrayList.
Mehrdad Afshari,
Zastanawiałem się, czy framework powinien ograniczyć T do typu „obiektowego”, ponieważ ArrayList domyślnie na to pozwala.
rajibdotnet
Jeśli chodzi o wycofanie niepublikowanych kolekcji, zobacz Informacje
ogólne uznane
@ Ant_222, ten blog został napisany prawie 15 lat temu. Myślę, że dowody z ostatniej dekady + wykazały, że leki generyczne nie są szkodliwe. :)
Scott Adams,
101
Za pomocą List<T>możesz zapobiec błędom przesyłania. Bardzo przydatne jest uniknięcie błędu rzutowania środowiska wykonawczego .
Przykład:
Tutaj (za pomocą ArrayList) możesz skompilować ten kod, ale później zobaczysz błąd wykonania.
ArrayList array1 =newArrayList();
array1.Add(1);
array1.Add("Pony");//No error at compile processint total =0;foreach(int num in array1){
total += num;//-->Runtime Error}
Jeśli używasz List, unikniesz następujących błędów:
List<int> list1 =newList<int>();
list1.Add(1);//list1.Add("Pony"); //<-- Error at compile processint total =0;foreach(int num in list1 ){
total += num;}
Możesz sprawdzić typ podczas pobierania z ArrayList, aby zapobiec błędom rzutowania. Teraz ludzie używają obiektów, dzięki czemu ArrayList nie jest już potrzebny.
Zamień
1
daję +1 uzasadnieniu, ale nadal możesz zrobić, jeśli (num is int) {} do listy tablic, aby uniknąć błędów
Mina Gabriel
Zapobiegaj błędom rzutowania i obciążeniom boksu. Powody, dla których generyczne leki są w ogóle.
marsze
26
Aby dodać do powyższych punktów. Używanie ArrayListw 64-bitowym systemie operacyjnym zajmuje 2x pamięć niż w 32-bitowym systemie operacyjnym. Tymczasem ogólna lista List<T>zużyje dużo mniej pamięci niż ArrayList.
na przykład, jeśli użyjemy 19 ArrayListMB w wersji 32-bitowej, to zajmie 39 MB w wersji 64-bitowej. Ale jeśli masz ogólną listę 8 List<int>MB w wersji 32-bitowej, zajmie to tylko 8,1 MB w wersji 64-bitowej, co jest ogromną różnicą 481% w porównaniu do ArrayList.
dotyczy to tylko przechowywania typów wartości, a nie typów referencyjnych. różnica wynika z faktu, że arraylist może zawierać tylko wskaźniki, a same dane muszą być przechowywane gdzie indziej. Z drugiej strony typy wartości mogą być przechowywane bezpośrednio na liście.
Rasmus Damgaard Nielsen
19
Kolejna różnica do dodania dotyczy synchronizacji wątków.
ArrayListzapewnia pewne bezpieczeństwo wątków dzięki właściwości Synchronized, która zwraca opakowanie bezpieczne dla wątków wokół kolekcji. Opakowanie działa poprzez zablokowanie całej kolekcji przy każdej operacji dodawania lub usuwania. Dlatego każdy wątek, który próbuje uzyskać dostęp do kolekcji, musi czekać na swoją kolej, aby przejąć jedną blokadę. Nie jest to skalowalne i może powodować znaczne obniżenie wydajności dużych kolekcji.
List<T>nie zapewnia synchronizacji wątków; kod użytkownika musi zapewniać całą synchronizację, gdy elementy są dodawane lub usuwane jednocześnie w wielu wątkach.
Nie twierdzę, że powinieneś użyć, ArrayListjeśli można tego uniknąć, ale jest to głupi powód. W końcu opakowanie jest całkowicie opcjonalne; jeśli nie potrzebujesz blokowania lub potrzebujesz bardziej szczegółowej kontroli, nie używaj opakowania.
Thorarin
1
Jeśli chcesz mieć bezpieczeństwo wątków, sugeruję zajrzenie do przestrzeni nazw System.Collections.Concurrent przed rozważeniem ArrayList.
Ykok
15
Prosta odpowiedź brzmi:
ArrayList jest nietypowy
Jest to typ obiektu, więc możesz przechowywać w nim dowolny typ danych.
W ArrayList można przechowywać dowolne wartości (typ wartości lub typ odwołania), takie jak łańcuch, int, pracownik i obiekt. (Uwaga i)
Nastąpi boksowanie i rozpakowanie.
Nie jest bezpieczny.
Jest starszy
Lista jest ogólna
Jest to typ typu, więc możesz określić T w czasie wykonywania.
Na podstawie deklaracji można zapisać tylko wartość typu T (łańcuch lub int lub pracownik lub obiekt). (Uwaga lub)
Wydajność została już wspomniana w kilku odpowiedziach jako czynnik różnicujący, ale aby odpowiedzieć na pytanie „ Jak wolniejsze jest ArrayList? ”I„ Dlaczego ogólnie jest wolniejszy?”, Spójrz poniżej.
Ilekroć typy wartości są używane jako elementy, wydajność dramatycznie spada ArrayList. Rozważ przypadek zwykłego dodawania elementów. Ze względu na to, że boks trwa, ponieważ ArrayListAdd tylko pobiera objectparametry, Garbage Collector zostaje zmuszony do wykonania znacznie większej ilości pracy niż przy użyciu List<T>.
Jaka jest różnica czasu? Co najmniej kilka razy wolniej niż z List<T>. Wystarczy spojrzeć na to, co dzieje się z kodem dodającym wartości 10 milionów int do ArrayListvs List<T>:
To różnica czasu bieg 5x w kolumnie „oznacza”, podświetlone na żółto. Zwróć także uwagę na różnicę w liczbie wyrzucania elementów bezużytecznych dla każdego z nich, podświetloną na czerwono (liczba uruchomień GC / 1000).
Korzystanie z narzędzia do profilowania, aby zobaczyć, co się dzieje, pokazuje, że większość czasu spędza się na tworzeniu GC , a nie na dodawaniu elementów. Brązowe słupki poniżej przedstawiają blokowanie aktywności Garbage Collector:
Podobne wyniki znajdują się w „CLR via C #” Jeffrey'a Richtera. Z rozdziału 12 (Ogólne):
[…] Kiedy kompiluję i uruchamiam kompilację wydania (z włączonymi optymalizacjami) tego programu na moim komputerze, otrzymuję następujące dane wyjściowe.
00: 00: 01.6246959 (GCs = 6) Lista <Int32> 00: 00: 10.8555008 (GCs = 390) ArrayList of Int32
00: 00: 02.5427847 (GCs = 4) Lista <String>
00: 00: 02.7944831 (GCs = 7 ) ArrayList of String
Dane wyjściowe pokazują, że użycie ogólnego algorytmu List z typem Int32 jest znacznie szybsze niż użycie nietypowego algorytmu ArrayList z Int32. W rzeczywistości różnica jest fenomenalna: 1,6 sekundy w porównaniu do prawie 11 sekund. To ~ 7 razy szybciej ! Ponadto użycie typu wartości (Int32) z ArrayList powoduje wiele operacji bokserskich, co powoduje 390 wyrzucania elementów bezużytecznych. Tymczasem algorytm List wymagał 6 odśmiecania.
List<T>, gdzie T jest typem wartości, jest szybsze niż ArrayList. To dlatego, żeList<T> unika się bokowania / rozpakowywania (gdzie T jest typem wartości).
Wiele źródeł mówi - zwykle ArrayListużywane tylko dla kompatybilności wstecznej. (nie jest to prawdziwa różnica, ale myślę, że to ważna uwaga).
Odbicie jest łatwiejsze z nongeneric ArrayListnastępnieList<T>
ArrayListma IsSynchronizedwłaściwość. Łatwo jest więc tworzyć i używać synchronizacji ArrayList. Nie znalazłem IsSynchronizednieruchomości dla List<T>. Należy również pamiętać, że ten rodzaj synchronizacji jest stosunkowo nieefektywny, msdn ):
var arraylist =newArrayList();var arrayListSyncronized =ArrayList.Synchronized(arraylist
Console.WriteLine($"syncronized {arraylist.IsSynchronized}");Console.WriteLine($"syncronized {arrayListSyncronized.IsSynchronized}");varlist=newList<object>();var listSyncronized =ArrayList.Synchronized(list);Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such propConsole.WriteLine($"syncronized {list.IsSynchronized}");//error, no such prop
ArrayListma ArrayList.SyncRootwłaściwość, której można użyć do synchronizacji ( msdn ). List<T>nie ma SyncRootwłaściwości, więc w poniższej konstrukcji musisz użyć jakiegoś obiektu, jeśli używasz List<T>:
ArrayList myCollection =newArrayList();lock(myCollection.SyncRoot)// ofcourse you can use another object for this goal{foreach(object item in myCollection){// ...}}
Nie zalecamy używania tej ArrayListklasy do nowych prac rozwojowych. Zamiast tego zalecamy użycie List<T>
klasy ogólnej . ArrayListKlasa jest przeznaczony do przechowywania heterogenicznych zbiory przedmiotów. Jednak nie zawsze oferuje najlepszą wydajność. Zamiast tego zalecamy następujące czynności:
W przypadku heterogenicznej kolekcji obiektów użyj typu List<Object>(w języku C #) lub List(Of Object)(w języku Visual Basic).
Aby uzyskać jednorodną kolekcję obiektów, użyj List<T>klasy.
Za pomocą „Listy” możesz zapobiec błędom przesyłania. Bardzo przydatne jest uniknięcie błędu rzutowania środowiska wykonawczego.
Przykład:
Tutaj (używając ArrayList) możesz skompilować ten kod, ale później zobaczysz błąd wykonania.
// Create a new ArrayListSystem.Collections.ArrayList mixedList =newSystem.Collections.ArrayList();// Add some numbers to the list
mixedList.Add(7);
mixedList.Add(21);// Add some strings to the list
mixedList.Add("Hello");
mixedList.Add("This is going to be a problem");System.Collections.ArrayList intList =newSystem.Collections.ArrayList();System.Collections.ArrayList strList =newSystem.Collections.ArrayList();foreach(object obj in mixedList){if(obj.GetType().Equals(typeof(int))){
intList.Add(obj);}elseif(obj.GetType().Equals(typeof(string))){
strList.Add(obj);}else{// error.}}
Co to dodaje poza odpowiedzią udzieloną przez Termas trzy lata wcześniej? Ma prawie taki sam dosłowny tekst, bez linków do źródła, bez odpowiedniego formatowania itp.
Douglas Zare
-3
Dla mnie chodzi przede wszystkim o znajomość swoich danych. Jeśli nadal będę rozszerzać swój kod na podstawie wydajności, musiałbym wybrać opcję Lista jako sposób na odszyfrowanie moich danych bez niepotrzebnego kroku ciągłego zastanawiania się nad typami, zwłaszcza „Typami niestandardowymi”. Jeśli maszyna rozumie różnicę i może określić na podstawie tego, z jakiego rodzaju danymi faktycznie mam do czynienia, to dlaczego miałbym przeszkadzać i marnować czas na wahania oznaczeń „JEŚLI JESZCZE”? Moja filozofia polega na tym, aby maszyna działała dla mnie, a nie dla mnie? Znajomość unikatowych różnic w różnych poleceniach kodu obiektowego znacznie przyczynia się do zwiększenia wydajności kodu.
List<>
w ogóle, podczas gdy to dotyczyList<object>
konkretnieOdpowiedzi:
Tak, właściwie.
List<T>
jest klasą ogólną. Obsługuje przechowywanie wartości określonego typu bez rzutowania do lub zobject
(co spowodowałoby obciążenie związane z boksem / rozpakowaniem, gdyT
jest to typ wartości wArrayList
przypadku).ArrayList
po prostu przechowujeobject
referencje. Jako zbiór rodzajowąList<T>
realizuje ogólneIEnumerable<T>
interfejs i mogą być łatwo stosowane w LINQ (bez potrzeby dokonywania jakiejkolwiekCast
lubOfType
połączenia).ArrayList
należy do dni, w których C # nie miał generycznych. Jest przestarzałe na korzyśćList<T>
. Nie powinieneś używaćArrayList
w nowym kodzie kierowanym na .NET> = 2.0, chyba że musisz połączyć się ze starym API, który go używa.źródło
ArrayList
w środowisku wykonawczym. Statycznie będzie to wymagało obsady za pomocąArrayList
.Za pomocą
List<T>
możesz zapobiec błędom przesyłania. Bardzo przydatne jest uniknięcie błędu rzutowania środowiska wykonawczego .Przykład:
Tutaj (za pomocą
ArrayList
) możesz skompilować ten kod, ale później zobaczysz błąd wykonania.Jeśli używasz
List
, unikniesz następujących błędów:Odniesienie: MSDN
źródło
Aby dodać do powyższych punktów. Używanie
ArrayList
w 64-bitowym systemie operacyjnym zajmuje 2x pamięć niż w 32-bitowym systemie operacyjnym. Tymczasem ogólna listaList<T>
zużyje dużo mniej pamięci niżArrayList
.na przykład, jeśli użyjemy 19
ArrayList
MB w wersji 32-bitowej, to zajmie 39 MB w wersji 64-bitowej. Ale jeśli masz ogólną listę 8List<int>
MB w wersji 32-bitowej, zajmie to tylko 8,1 MB w wersji 64-bitowej, co jest ogromną różnicą 481% w porównaniu do ArrayList.Źródło: Lista ArrayList vs. ogólna dla typów pierwotnych i 64-bitowych
źródło
Kolejna różnica do dodania dotyczy synchronizacji wątków.
Więcej informacji tutaj Synchronizacja wątków w .Net Framework
źródło
ArrayList
jeśli można tego uniknąć, ale jest to głupi powód. W końcu opakowanie jest całkowicie opcjonalne; jeśli nie potrzebujesz blokowania lub potrzebujesz bardziej szczegółowej kontroli, nie używaj opakowania.Prosta odpowiedź brzmi:
ArrayList jest nietypowy
Lista jest ogólna
Przykład:
Przeczytaj oficjalny dokument Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/
Uwaga : powinieneś znać Generics, zanim zrozumiesz różnicę: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
źródło
ArrayList
jest zbiorem danych różnych typów, podczas gdyList<>
jest zbiorem podobnego rodzaju własnych oddziałów.źródło
ArrayList
nie są bezpieczne typu, podczas gdyList<T>
są bezpieczne typu. Prosty :).źródło
Wydajność została już wspomniana w kilku odpowiedziach jako czynnik różnicujący, ale aby odpowiedzieć na pytanie „ Jak wolniejsze jest
ArrayList
? ”I„ Dlaczego ogólnie jest wolniejszy?”, Spójrz poniżej.Ilekroć typy wartości są używane jako elementy, wydajność dramatycznie spada
ArrayList
. Rozważ przypadek zwykłego dodawania elementów. Ze względu na to, że boks trwa, ponieważArrayList
Add tylko pobieraobject
parametry, Garbage Collector zostaje zmuszony do wykonania znacznie większej ilości pracy niż przy użyciuList<T>
.Jaka jest różnica czasu? Co najmniej kilka razy wolniej niż z
List<T>
. Wystarczy spojrzeć na to, co dzieje się z kodem dodającym wartości 10 milionów int doArrayList
vsList<T>
:To różnica czasu bieg 5x w kolumnie „oznacza”, podświetlone na żółto. Zwróć także uwagę na różnicę w liczbie wyrzucania elementów bezużytecznych dla każdego z nich, podświetloną na czerwono (liczba uruchomień GC / 1000).
Korzystanie z narzędzia do profilowania, aby zobaczyć, co się dzieje, pokazuje, że większość czasu spędza się na tworzeniu GC , a nie na dodawaniu elementów. Brązowe słupki poniżej przedstawiają blokowanie aktywności Garbage Collector:
Szczegółową analizę tego, co dzieje się w powyższym
ArrayList
scenariuszu, napisałem tutaj https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ .Podobne wyniki znajdują się w „CLR via C #” Jeffrey'a Richtera. Z rozdziału 12 (Ogólne):
źródło
Myślę, że różnice między
ArrayList
iList<T>
są:List<T>
, gdzie T jest typem wartości, jest szybsze niżArrayList
. To dlatego, żeList<T>
unika się bokowania / rozpakowywania (gdzie T jest typem wartości).ArrayList
używane tylko dla kompatybilności wstecznej. (nie jest to prawdziwa różnica, ale myślę, że to ważna uwaga).ArrayList
następnieList<T>
ArrayList
maIsSynchronized
właściwość. Łatwo jest więc tworzyć i używać synchronizacjiArrayList
. Nie znalazłemIsSynchronized
nieruchomości dlaList<T>
. Należy również pamiętać, że ten rodzaj synchronizacji jest stosunkowo nieefektywny, msdn ):ArrayList
maArrayList.SyncRoot
właściwość, której można użyć do synchronizacji ( msdn ).List<T>
nie maSyncRoot
właściwości, więc w poniższej konstrukcji musisz użyć jakiegoś obiektu, jeśli używaszList<T>
:źródło
Jak wspomniano w dokumentacji .NET Framework
Zobacz także Nie należy używać kolekcji nietypowych
źródło
Za pomocą „Listy” możesz zapobiec błędom przesyłania. Bardzo przydatne jest uniknięcie błędu rzutowania środowiska wykonawczego.
Przykład:
Tutaj (używając ArrayList) możesz skompilować ten kod, ale później zobaczysz błąd wykonania.
źródło
Dla mnie chodzi przede wszystkim o znajomość swoich danych. Jeśli nadal będę rozszerzać swój kod na podstawie wydajności, musiałbym wybrać opcję Lista jako sposób na odszyfrowanie moich danych bez niepotrzebnego kroku ciągłego zastanawiania się nad typami, zwłaszcza „Typami niestandardowymi”. Jeśli maszyna rozumie różnicę i może określić na podstawie tego, z jakiego rodzaju danymi faktycznie mam do czynienia, to dlaczego miałbym przeszkadzać i marnować czas na wahania oznaczeń „JEŚLI JESZCZE”? Moja filozofia polega na tym, aby maszyna działała dla mnie, a nie dla mnie? Znajomość unikatowych różnic w różnych poleceniach kodu obiektowego znacznie przyczynia się do zwiększenia wydajności kodu.
Tom Johnson (One Entry ... One Exit)
źródło