ArrayList vs List <> in C #


412

Jaka jest różnica między ArrayListi List<>w C #?

Czy tylko to List<>ma typ, a ArrayListnie ma?



5
To ścisłe pytanie, ale myślę, że nie do końca powiela się. To pyta List<>w ogóle, podczas gdy to dotyczy List<object>konkretnie
goodeye

Znalazłem ten bardzo pomocny blog, może pomóc. Myślałem, że powinienem udostępnić link: fintechexplained.blogspot.co.uk/2017/07/…
InfoLearner

Odpowiedzi:


533

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 = new ArrayList();
array1.Add(1);
array1.Add("Pony"); //No error at compile process
int 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 = new List<int>();
list1.Add(1);
//list1.Add("Pony"); //<-- Error at compile process
int total = 0;
foreach (int num in list1 )
{
 total += num;
}

Odniesienie: MSDN


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.

Źródło: Lista ArrayList vs. ogólna dla typów pierwotnych i 64-bitowych


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

Więcej informacji tutaj Synchronizacja wątków w .Net Framework


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)
  • Boksowanie i rozpakowywanie się nie nastąpi.
  • Wpisz bezpieczny.
  • Jest nowszy.

Przykład:

ArrayList arrayList = new ArrayList();
List<int> list = new List<int>();

arrayList.Add(1);
arrayList.Add("String");
arrayList.Add(new object());


list.Add(1);
list.Add("String");                 // Compile-time Error
list.Add(new object());             // Compile-time Error

Przeczytaj oficjalny dokument Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/

wprowadź opis zdjęcia tutaj

Uwaga : powinieneś znać Generics, zanim zrozumiesz różnicę: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/


4

ArrayListjest zbiorem danych różnych typów, podczas gdy List<>jest zbiorem podobnego rodzaju własnych oddziałów.



2

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>: wprowadź opis zdjęcia tutaj

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: wprowadź opis zdjęcia tutaj

Szczegółową analizę tego, co dzieje się w powyższym ArrayListscenariuszu, 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):

[…] 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.


1

Myślę, że różnice między ArrayListi List<T>są:

  1. 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).
  2. 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).
  3. Odbicie jest łatwiejsze z nongeneric ArrayListnastępnieList<T>
  4. 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 = new ArrayList();
    var arrayListSyncronized = ArrayList.Synchronized(arraylist
    Console.WriteLine($"syncronized {arraylist.IsSynchronized}");
    Console.WriteLine($"syncronized {arrayListSyncronized.IsSynchronized}");
    
    var list = new List<object>();
    var listSyncronized = ArrayList.Synchronized(list);
    Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such prop
    Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such prop
  5. 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 = new ArrayList();
    lock(myCollection.SyncRoot) //  ofcourse you can use another object for this goal
    {
        foreach (object item in myCollection)
        {
            // ...
        }
    }

0

Jak wspomniano w dokumentacji .NET Framework

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.

Zobacz także Nie należy używać kolekcji nietypowych

tabela pokazuje, jak nieogólne typy kolekcji można zastąpić ich ogólnymi odpowiednikami


-2

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 ArrayList


    System.Collections.ArrayList mixedList = new System.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 = new System.Collections.ArrayList();
    System.Collections.ArrayList strList = new System.Collections.ArrayList();


    foreach (object obj in mixedList)
    {
        if (obj.GetType().Equals(typeof(int)))
        {
            intList.Add(obj);
        }
        else if (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.

Tom Johnson (One Entry ... One Exit)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.