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 =newArrayList();
array1.Add(1);
array1.Add("Pony");//No error at compile processint total =0;foreach(int num in array1){
total += num;//-->Runtime Error}
Wenn Sie verwenden List, vermeiden Sie diese Fehler:
List<int> list1 =newList<int>();
list1.Add(1);//list1.Add("Pony"); //<-- Error at compile processint total =0;foreach(int num in list1 ){
total += num;}
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.
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.
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)
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>:
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:
Ä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.
Ich denke, die Unterschiede zwischen ArrayListund List<T>sind:
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).
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).
Reflexion ist einfacher , mit nicht - generischen ArrayListdannList<T>
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 =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
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 =newArrayList();lock(myCollection.SyncRoot)// ofcourse you can use another object for this goal{foreach(object item in myCollection){// ...}}
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.
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 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.}}
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.
List<>
im Allgemeinen, während dasList<object>
speziell fragtAntworten:
Ja so ziemlich.
List<T>
ist eine generische Klasse. Es unterstützt das Speichern von Werten eines bestimmten Typs ohne Umwandlung in oder vonobject
(was zu einem Box- / Unboxing-Overhead geführt hätte, wennT
es sich in diesemArrayList
Fall um einen Werttyp handelt ).ArrayList
speichert einfachobject
Referenzen. Als generische Sammlung,List<T>
implementiert die generischeIEnumerable<T>
Schnittstelle und kann leicht in LINQ verwendet werden (ohne zu erfordernCast
oderOfType
Anruf).ArrayList
gehört zu den Tagen, in denen C # keine Generika hatte. Es ist zugunsten von veraltetList<T>
. Sie sollten keinenArrayList
neuen Code verwenden, der auf .NET> = 2.0 abzielt, es sei denn, Sie müssen eine Schnittstelle mit einer alten API herstellen, die ihn verwendet.quelle
ArrayList
zur Laufzeit. Statisch erfordert es jedoch eine Besetzung mitArrayList
.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.Wenn Sie verwenden
List
, vermeiden Sie diese Fehler:Referenz: MSDN
quelle
Zu den obigen Punkten hinzufügen. Die Verwendung
ArrayList
im 64-Bit-Betriebssystem benötigt 2x Speicher als die Verwendung im 32-Bit-Betriebssystem. In der Zwischenzeit benötigt die generische ListeList<T>
viel weniger Speicher als dieArrayList
.Wenn wir beispielsweise
ArrayList
19 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
quelle
Ein weiterer Unterschied besteht in der Thread-Synchronisation.
Weitere Informationen hier Thread-Synchronisation im .Net Framework
quelle
ArrayList
wenn 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.Einfache Antwort ist,
ArrayList ist nicht generisch
Liste ist generisch
Beispiel:
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/
Hinweis : Sie sollten Generics kennen, bevor Sie den Unterschied verstehen: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
quelle
ArrayList
ist die Sammlung von Daten verschiedener Arten, währendList<>
die Sammlung von ähnlichen Arten seiner eigenen Abhängigkeiten ist.quelle
ArrayList
sind nicht typsicher, wohingegenList<T>
typsicher sind. Einfach :).quelle
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 - daArrayList
'Add' nurobject
Parameter benötigt - wird der Garbage Collector dazu veranlasst, viel mehr Arbeit als mit auszuführenList<T>
.Wie groß ist der Zeitunterschied? Mindestens mehrmals langsamer als mit
List<T>
. Schauen Sie sich an, was mit Code passiert, der einemArrayList
vs 10 mil int-Werte hinzufügtList<T>
: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:
Ich habe
ArrayList
hier 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):
quelle
Ich denke, die Unterschiede zwischen
ArrayList
undList<T>
sind:List<T>
, wobei T ein Werttyp ist, ist schneller alsArrayList
. Dies liegt daran, dassList<T>
Boxen / Unboxing vermieden wird (wobei T ein Werttyp ist).ArrayList
nur aus Gründen der Abwärtskompatibilität verwendet. (ist kein wirklicher Unterschied, aber ich denke, es ist ein wichtiger Hinweis).ArrayList
dannList<T>
ArrayList
hatIsSynchronized
Eigentum. So ist es einfach, synchronisiert zu erstellen und zu verwendenArrayList
. Ich habe keineIsSynchronized
Immobilie für gefundenList<T>
. Beachten Sie auch, dass diese Art der Synchronisation relativ ineffizient ist ( msdn ):ArrayList
hat eineArrayList.SyncRoot
Eigenschaft, die zur Synchronisation verwendet werden kann ( msdn ).List<T>
hat keineSyncRoot
Eigenschaft, daher müssen Sie in der folgenden Konstruktion ein Objekt verwenden, wenn Sie verwendenList<T>
:quelle
Wie in der .NET Framework- Dokumentation erwähnt
Siehe auch Nicht generische Sammlungen sollten nicht verwendet werden
quelle
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.
quelle
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)
quelle