ArrayList vs List <> in C #


412

Was ist der Unterschied zwischen ArrayListund List<>in C #?

Hat nur List<>ein Typ eine Weile ArrayListnicht?


5
mögliches Duplikat von ArrayList vs List <Objekt>
John Saunders

5
Es ist eine enge Frage, aber ich denke nicht genau doppelt. Dies fragt List<>im Allgemeinen, während das List<object>speziell fragt
goodeye

Fand diesen sehr hilfreichen Blog, es könnte helfen. Ich dachte, ich sollte den Link teilen: fintechexplained.blogspot.co.uk/2017/07/…
InfoLearner

Antworten:


533

Ja so ziemlich. List<T>ist eine generische Klasse. Es unterstützt das Speichern von Werten eines bestimmten Typs ohne Umwandlung in oder von object(was zu einem Box- / Unboxing-Overhead geführt hätte, wenn Tes sich in diesem ArrayListFall um einen Werttyp handelt ). ArrayListspeichert einfach objectReferenzen. Als generische Sammlung, List<T>implementiert die generische IEnumerable<T>Schnittstelle und kann leicht in LINQ verwendet werden (ohne zu erfordern Castoder OfTypeAnruf).

ArrayListgehört zu den Tagen, in denen C # keine Generika hatte. Es ist zugunsten von veraltet List<T>. Sie sollten keinen ArrayListneuen Code verwenden, der auf .NET> = 2.0 abzielt, es sei denn, Sie müssen eine Schnittstelle mit einer alten API herstellen, die ihn verwendet.


Würde es Ihnen etwas ausmachen zu erklären, warum Sie "Boxen" und nicht "Casting" verwendet haben? Was passiert hier beim Boxen? Werden Objekte zugewiesen / freigegeben?
Benjamin Gruenbaum

2
@BenjaminGruenbaum Sie haben Recht, dass das Casting allgemeiner wäre. Der wirkliche Unterschied zur Laufzeit besteht jedoch darin, dass Sie sich mit Werttypen befassen (was ich beim Schreiben von "Boxen" angenommen habe). Bei Referenztypen ist das Verhalten praktisch das gleiche wie ArrayListzur Laufzeit. Statisch erfordert es jedoch eine Besetzung mit ArrayList.
Mehrdad Afshari

Ich habe mich gefragt, ob das Framework T auf den Typ "Objekt" beschränken soll, da ArrayList dies implizit zulässt.
Rajibdotnet

Bezüglich der
Ablehnung nicht

@ Ant_222, dieser Blog wurde vor fast 15 Jahren geschrieben. Ich denke, die Beweise des letzten Jahrzehnts haben gezeigt, dass Generika nicht schädlich sind. :)
Scott Adams

101

Mit können List<T>Sie Casting-Fehler vermeiden. Es ist sehr nützlich, einen Laufzeit- Casting-Fehler zu vermeiden .

Beispiel:

Hier (mit ArrayList) können Sie diesen Code kompilieren, aber später wird ein Ausführungsfehler angezeigt.

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
}

Wenn Sie verwenden List, vermeiden Sie diese Fehler:

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

Referenz: MSDN


Sie können den Typ beim Abrufen aus der ArrayList überprüfen, um Casting-Fehler zu vermeiden. Heutzutage verwenden Benutzer Objekte, sodass ArrayList nicht mehr benötigt wird.
Wechseln Sie am

1
Ich +1 zur Rechtfertigung, aber Sie können immer noch tun, wenn (num ist int) {} zu Ihrer Array-Liste, um Fehler zu vermeiden
Mina Gabriel

Verhindern Sie Casting-Fehler und Box-Overhead. So ziemlich die Gründe für Generika im Allgemeinen.
Marsze

26

Zu den obigen Punkten hinzufügen. Die Verwendung ArrayListim 64-Bit-Betriebssystem benötigt 2x Speicher als die Verwendung im 32-Bit-Betriebssystem. In der Zwischenzeit benötigt die generische Liste List<T>viel weniger Speicher als die ArrayList.

Wenn wir beispielsweise ArrayList19 MB in 32-Bit verwenden, werden in 64-Bit 39 MB benötigt. Aber wenn Sie eine generische Liste habenList<int> von 8 MB in 32-Bit haben, werden nur 8,1 MB in 64-Bit benötigt, was im Vergleich zu ArrayList einen Unterschied von 481% darstellt.

Quelle: ArrayList's vs. generic List für primitive Typen und 64-Bit


5
Dies gilt nur für das Speichern von Werttypen, nicht für Referenztypen. Der Unterschied beruht auf der Tatsache, dass eine Arrayliste nur Zeiger enthalten kann und die Daten selbst an anderer Stelle gespeichert werden müssen. Andererseits können Werttypen direkt in einer Liste gespeichert werden.
Rasmus Damgaard Nielsen

19

Ein weiterer Unterschied besteht in der Thread-Synchronisation.

ArrayListBietet eine gewisse Thread-Sicherheit durch die Synchronized-Eigenschaft, die einen thread-sicheren Wrapper um die Sammlung zurückgibt. Der Wrapper sperrt die gesamte Sammlung bei jedem Hinzufügen oder Entfernen. Daher muss jeder Thread, der versucht, auf die Sammlung zuzugreifen, warten, bis er an der Reihe ist, um die eine Sperre zu erhalten. Dies ist nicht skalierbar und kann bei großen Sammlungen zu erheblichen Leistungseinbußen führen.

List<T>bietet keine Thread-Synchronisation; Der Benutzercode muss die gesamte Synchronisierung bereitstellen, wenn Elemente in mehreren Threads gleichzeitig hinzugefügt oder entfernt werden.

Weitere Informationen hier Thread-Synchronisation im .Net Framework


Ich sage nicht, dass Sie verwenden sollten, ArrayListwenn es vermieden werden kann, aber das ist ein dummer Grund. Der Wrapper ist schließlich völlig optional; Wenn Sie keine Sperre benötigen oder eine detailliertere Steuerung benötigen, verwenden Sie den Wrapper nicht.
Thorarin

1
Wenn Sie Thread-Sicherheit wünschen, empfehlen wir Ihnen, sich den System.Collections.Concurrent-Namespace anzusehen, bevor Sie ArrayList in Betracht ziehen.
Ykok

15

Einfache Antwort ist,

ArrayList ist nicht generisch

  • Da es sich um einen Objekttyp handelt, können Sie einen beliebigen Datentyp darin speichern.
  • Sie können beliebige Werte (Werttyp oder Referenztyp) wie Zeichenfolge, int, Mitarbeiter und Objekt in der ArrayList speichern. (Hinweis und)
  • Boxen und Unboxing wird passieren.
  • Nicht typsicher.
  • Es ist älter.

Liste ist generisch

  • Da es sich um einen Typ handelt, können Sie das T zur Laufzeit angeben.
  • Sie können einen einzigen Wert vom Typ T (Zeichenfolge oder int oder Mitarbeiter oder Objekt) basierend auf der Deklaration speichern. (Notiz oder)
  • Boxen und Unboxen wird nicht passieren.
  • Geben Sie safe ein.
  • Es ist neuer.

Beispiel:

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

Bitte lesen Sie das offizielle Microsoft-Dokument : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/

Geben Sie hier die Bildbeschreibung ein

Hinweis : Sie sollten Generics kennen, bevor Sie den Unterschied verstehen: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/


4

ArrayListist die Sammlung von Daten verschiedener Arten, während List<>die Sammlung von ähnlichen Arten seiner eigenen Abhängigkeiten ist.


3

ArrayListsind nicht typsicher, wohingegen List<T>typsicher sind. Einfach :).


2

Die Leistung wurde bereits in mehreren Antworten als Differenzierungsfaktor erwähnt, aber um das „ Wie viel langsamer ist das ArrayList? "Und" Warum ist es insgesamt langsamer?”, Schauen Sie unten.

Immer wenn Werttypen als Elemente verwendet werden, sinkt die Leistung dramatisch mit ArrayList. Betrachten Sie den Fall des einfachen Hinzufügens von Elementen. Aufgrund des laufenden Boxens - da ArrayList'Add' nur objectParameter benötigt - wird der Garbage Collector dazu veranlasst, viel mehr Arbeit als mit auszuführen List<T>.

Wie groß ist der Zeitunterschied? Mindestens mehrmals langsamer als mit List<T>. Schauen Sie sich an, was mit Code passiert, der einem ArrayListvs 10 mil int-Werte hinzufügt List<T>: Geben Sie hier die Bildbeschreibung ein

Das ist ein Laufzeitunterschied von 5x in der gelb hervorgehobenen Spalte "Mittelwert". Beachten Sie auch den Unterschied in der Anzahl der jeweils durchgeführten Garbage Collections, die rot hervorgehoben sind (Anzahl der GCs / 1000-Läufe).

Die Verwendung eines Profilers, um schnell zu sehen, was los ist, zeigt, dass die meiste Zeit mit GCs verbracht wird, anstatt tatsächlich Elemente hinzuzufügen. Die braunen Balken unten stellen die blockierende Garbage Collector-Aktivität dar: Geben Sie hier die Bildbeschreibung ein

Ich habe ArrayListhier https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ eine detaillierte Analyse der oben beschriebenen Szenarien verfasst .

Ähnliche Ergebnisse finden sich in „CLR via C #“ von Jeffrey Richter. Aus Kapitel 12 (Generika):

[…] Wenn ich einen Release-Build (mit aktivierten Optimierungen) dieses Programms auf meinem Computer kompiliere und ausführe, erhalte ich die folgende Ausgabe.

00: 00: 01.6246959 (GCs = 6) Liste <Int32>
00: 00: 10.8555008 (GCs = 390) ArrayList von Int32
00: 00: 02.5427847 (GCs = 4) Liste <String>
00: 00: 02.7944831 (GCs = 7 ) ArrayList of String

Die Ausgabe hier zeigt, dass die Verwendung des generischen Listenalgorithmus mit dem Int32-Typ viel schneller ist als die Verwendung des nicht generischen ArrayList-Algorithmus mit Int32. Tatsächlich ist der Unterschied phänomenal: 1,6 Sekunden gegenüber fast 11 Sekunden. Das ist ~ 7 mal schneller ! Darüber hinaus führt die Verwendung eines Werttyps (Int32) mit ArrayList dazu, dass viele Boxvorgänge ausgeführt werden, was zu 390 Speicherbereinigungen führt. In der Zwischenzeit benötigte der List-Algorithmus 6 Garbage Collections.


1

Ich denke, die Unterschiede zwischen ArrayListund List<T>sind:

  1. List<T>, wobei T ein Werttyp ist, ist schneller als ArrayList. Dies liegt daran, dass List<T>Boxen / Unboxing vermieden wird (wobei T ein Werttyp ist).
  2. Viele Quellen sagen - normalerweise ArrayListnur aus Gründen der Abwärtskompatibilität verwendet. (ist kein wirklicher Unterschied, aber ich denke, es ist ein wichtiger Hinweis).
  3. Reflexion ist einfacher , mit nicht - generischen ArrayListdannList<T>
  4. ArrayListhat IsSynchronizedEigentum. So ist es einfach, synchronisiert zu erstellen und zu verwenden ArrayList. Ich habe keine IsSynchronizedImmobilie für gefunden List<T>. Beachten Sie auch, dass diese Art der Synchronisation relativ ineffizient ist ( 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. ArrayListhat eine ArrayList.SyncRootEigenschaft, die zur Synchronisation verwendet werden kann ( msdn ). List<T>hat keine SyncRootEigenschaft, daher müssen Sie in der folgenden Konstruktion ein Objekt verwenden, wenn Sie verwenden List<T>:

    ArrayList myCollection = new ArrayList();
    lock(myCollection.SyncRoot) //  ofcourse you can use another object for this goal
    {
        foreach (object item in myCollection)
        {
            // ...
        }
    }

0

Wie in der .NET Framework- Dokumentation erwähnt

Wir empfehlen nicht, die ArrayListKlasse für Neuentwicklungen zu verwenden. Stattdessen empfehlen wir Ihnen, die generische List<T> Klasse zu verwenden. Die ArrayListKlasse ist für heterogene Sammlungen von Objekten ausgelegt. Es bietet jedoch nicht immer die beste Leistung. Stattdessen empfehlen wir Folgendes:

  • Verwenden Sie für eine heterogene Sammlung von Objekten den Typ List<Object>(in C #) oder List(Of Object)(in Visual Basic).
  • Verwenden Sie für eine homogene Sammlung von Objekten die List<T>Klasse.

Siehe auch Nicht generische Sammlungen sollten nicht verwendet werden

Die Tabelle zeigt, wie die nicht generischen Sammlungstypen durch ihre generischen Gegenstücke ersetzt werden können


-2

Mit "Liste" können Sie Casting-Fehler vermeiden. Es ist sehr nützlich, einen Laufzeit-Casting-Fehler zu vermeiden.

Beispiel:

Hier (mit ArrayList) können Sie diesen Code kompilieren, aber später wird ein Ausführungsfehler angezeigt.

    // 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.
        }
    }

Was fügt dies über die drei Jahre zuvor angegebenen Antworttermine hinaus hinzu? Es hat fast den gleichen Text wörtlich, ohne auf die Quelle zu verlinken, ohne richtig zu formatieren usw.
Douglas Zare

-3

Für mich geht es darum, Ihre Daten zu kennen. Wenn ich meinen Code aus Effizienzgründen weiter ausbauen möchte, muss ich die Option Liste auswählen, um meine Daten zu entschlüsseln, ohne mich unnötig über Typen, insbesondere über benutzerdefinierte Typen, zu wundern. Wenn die Maschine den Unterschied versteht und feststellen kann, um welche Art von Daten es sich tatsächlich handelt, warum sollte ich mich dann in den Weg stellen und Zeit damit verschwenden, die Drehungen der Bestimmungen "WENN DANN SONST" zu durchlaufen? Meine Philosophie ist es, die Maschine für mich arbeiten zu lassen, anstatt dass ich an der Maschine arbeite? Die Kenntnis der einzigartigen Unterschiede verschiedener Objektcodebefehle trägt wesentlich dazu bei, Ihren Code so effizient wie möglich zu gestalten.

Tom Johnson (Ein Eintrag ... Ein Ausgang)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.