MyClass[] array;
List<MyClass> list;
Was sind die Szenarien, in denen eines dem anderen vorzuziehen ist? Und warum?
MyClass[] array;
List<MyClass> list;
Was sind die Szenarien, in denen eines dem anderen vorzuziehen ist? Und warum?
Antworten:
In der Realität ist es selten, dass Sie ein Array verwenden möchten. Verwenden List<T>
Sie auf jeden Fall eine, wenn Sie Daten hinzufügen / entfernen möchten, da die Größenänderung von Arrays teuer ist. Wenn Sie wissen, dass die Daten eine feste Länge haben und aus einem bestimmten Grund (nach dem Benchmarking) eine Mikrooptimierung durchführen möchten, kann ein Array hilfreich sein.
List<T>
bietet viel mehr Funktionalität als ein Array (obwohl LINQ es ein wenig ausgleicht) und ist fast immer die richtige Wahl. Abgesehen von params
Argumenten natürlich. ;-p
Als Zähler - List<T>
ist eindimensional; Wobei Sie rechteckige (usw.) Arrays wie int[,]
oder haben, string[,,]
aber es gibt andere Möglichkeiten, solche Daten (falls erforderlich) in einem Objektmodell zu modellieren.
Siehe auch:
Das heißt, ich eine machen viel für die Verwendung von Arrays in meinem protobuf-net Projekt; ganz für die Leistung:
byte[]
ist a für die Codierung ziemlich wichtig.byte[]
Buffer, den ich fülle, bevor ich ihn an den zugrunde liegenden Stream (und vv) sende. schneller als BufferedStream
etc;Foo[]
anstatt List<Foo>
), da die Größe nach dem Erstellen festgelegt ist und sehr schnell sein muss.Dies ist jedoch definitiv eine Ausnahme. Für die allgemeine Branchenverarbeitung List<T>
gewinnt jedes Mal ein.
Wirklich nur zu antworten, um einen Link hinzuzufügen, von dem ich überrascht bin, dass er noch nicht erwähnt wurde: Eric's Lipperts Blogeintrag zu "Arrays gelten als etwas schädlich".
Sie können anhand des Titels beurteilen, dass die Verwendung von Sammlungen vorgeschlagen wird, wo immer dies praktikabel ist - aber wie Marc zu Recht betont, gibt es viele Stellen, an denen ein Array wirklich die einzige praktische Lösung ist.
Ungeachtet der anderen empfohlenen Antworten List<T>
sollten Sie bei der Handhabung Arrays verwenden:
List<T>
Here-Arrays anstelle eines Byte-Arrays?
Es sei denn, Sie befassen sich wirklich mit der Leistung, und damit meine ich: "Warum verwenden Sie .Net anstelle von C ++?" Sie sollten bei List <> bleiben. Es ist einfacher zu warten und erledigt die ganze Drecksarbeit, die Größe eines Arrays hinter den Kulissen für Sie zu ändern. (Falls erforderlich, ist List <> ziemlich klug bei der Auswahl von Array-Größen, sodass dies normalerweise nicht erforderlich ist.)
Arrays sollten gegenüber List bevorzugt verwendet werden, wenn die Unveränderlichkeit der Sammlung selbst Teil des Vertrags zwischen dem Kunden- und Anbietercode ist (nicht unbedingt die Unveränderlichkeit der Elemente in der Sammlung) UND wenn IEnumerable nicht geeignet ist.
Zum Beispiel,
var str = "This is a string";
var strChars = str.ToCharArray(); // returns array
Es ist klar, dass die Änderung von "strChars" das ursprüngliche "str" -Objekt nicht mutiert, unabhängig davon, ob der zugrunde liegende Typ von "str" auf Implementierungsebene bekannt ist.
Aber nehmen wir das an
var str = "This is a string";
var strChars = str.ToCharList(); // returns List<char>
strChars.Insert(0, 'X');
In diesem Fall ist aus diesem Code-Snippet allein nicht ersichtlich, ob die Einfügemethode das ursprüngliche "str" -Objekt mutiert oder nicht. Es erfordert Kenntnisse über String auf Implementierungsebene, um diese Bestimmung zu treffen, was den Design by Contract-Ansatz bricht. Im Fall von String ist es keine große Sache, aber es kann in fast jedem anderen Fall eine große Sache sein. Das Festlegen der Liste auf schreibgeschützt hilft zwar, führt jedoch zu Laufzeitfehlern und nicht zur Kompilierungszeit.
To
, ein Objekt erstellen wird, das die ursprüngliche Instanz nicht ändern kann, im Gegensatz dazu strChars as char[]
, wenn dies gültig ist, würde dies bedeuten, dass Sie jetzt das ursprüngliche Objekt ändern können.
str
intern ein Array verwendet wird und ToCharArray
ein Verweis auf dieses Array zurückgegeben wird, kann der Client str
durch Ändern der Elemente dieses Arrays mutieren , auch wenn die Größe fest bleibt. Sie schreiben jedoch: "Es ist klar, dass eine Änderung von" strChars "das ursprüngliche" str "-Objekt nicht mutiert." Was fehlt mir hier? Soweit ich sehen kann, kann der Client in beiden Fällen Zugriff auf die interne Darstellung haben, und dies würde unabhängig vom Typ eine Mutation ermöglichen.
Wenn ich genau weiß, wie viele Elemente ich benötige, sagen wir, ich benötige 5 Elemente und immer nur 5 Elemente, dann verwende ich ein Array. Ansonsten benutze ich einfach eine Liste <T>.
In den meisten List
Fällen würde die Verwendung von a ausreichen. A List
verwendet ein internes Array, um seine Daten zu verarbeiten, und ändert automatisch die Größe des Arrays, wenn mehr Elemente zur List
aktuellen Kapazität hinzugefügt werden. Dies macht die Verwendung einfacher als bei einem Array, bei dem Sie die Kapazität im Voraus kennen müssen.
Weitere Informationen zu Listen in C # oder zum Dekompilieren finden Sie unter http://msdn.microsoft.com/en-us/library/ms379570(v=vs.80).aspx#datastructures20_1_topic5System.Collections.Generic.List<T>
.
Wenn Sie mehrdimensionale Daten benötigen (z. B. mithilfe einer Matrix oder in der Grafikprogrammierung), würden Sie wahrscheinlich stattdessen eine array
verwenden.
Wie immer, wenn Speicher oder Leistung ein Problem sind, messen Sie es! Andernfalls könnten Sie falsche Annahmen über den Code treffen.
Arrays Vs. Listen sind ein klassisches Problem zwischen Wartbarkeit und Leistung. Die Faustregel, die fast alle Entwickler befolgen, lautet, dass Sie für beide fotografieren sollten. Wenn sie jedoch in Konflikt geraten, wählen Sie die Wartbarkeit gegenüber der Leistung. Die Ausnahme von dieser Regel ist, wenn sich die Leistung bereits als Problem erwiesen hat. Wenn Sie dieses Prinzip in Arrays Vs. Listen, dann erhalten Sie Folgendes:
Verwenden Sie stark typisierte Listen, bis Sie auf Leistungsprobleme stoßen. Wenn Sie auf ein Leistungsproblem stoßen, entscheiden Sie, ob ein Ausfall auf Arrays Ihrer Lösung mehr Leistung bringt, als dass dies Ihre Lösung in Bezug auf die Wartung beeinträchtigt.
Eine andere Situation, die noch nicht erwähnt wurde, besteht darin, dass eine große Anzahl von Elementen vorhanden ist, von denen jedes aus einem festen Bündel verwandter, aber unabhängiger Variablen besteht, die zusammenkleben (z. B. die Koordinaten eines Punkts oder die Eckpunkte eines 3D-Dreiecks). Ein Array von exponierten Feldstrukturen ermöglicht es, seine Elemente effizient "an Ort und Stelle" zu modifizieren - was mit keinem anderen Sammlungstyp möglich ist. Da ein Array von Strukturen seine Elemente nacheinander im RAM hält, können sequentielle Zugriffe auf Array-Elemente sehr schnell erfolgen. In Situationen, in denen Code viele aufeinanderfolgende Durchläufe durch ein Array ausführen muss, kann ein Array von Strukturen ein Array oder eine andere Sammlung von Klassenobjektreferenzen um den Faktor 2: 1 übertreffen. des Weiteren,
Obwohl die Größe von Arrays nicht geändert werden kann, ist es nicht schwierig, dass Code eine Array-Referenz zusammen mit der Anzahl der verwendeten Elemente speichert und das Array nach Bedarf durch ein größeres ersetzt. Alternativ könnte man leicht Code für einen Typ schreiben, der sich ähnlich wie a List<T>
verhält, aber seinen Hintergrundspeicher freigibt, so dass man entweder MyPoints.Add(nextPoint);
oder sagen kann MyPoints.Items[23].X += 5;
. Beachten Sie, dass letzteres nicht unbedingt eine Ausnahme auslösen würde, wenn Code versuchen würde, über das Ende der Liste hinaus zuzugreifen, aber die Verwendung ansonsten konzeptionell ziemlich ähnlich wäre List<T>
.
Point[] arr;
, z arr[3].x+=q;
. B. kann Code sagen, z . Mit zB List<Point> list
müsste man stattdessen sagen Point temp=list[3]; temp.x+=q; list[3]=temp;
. Es wäre hilfreich, wenn List<T>
eine Methode hätte Update<TP>(int index, ActionByRefRef<T,TP> proc, ref TP params)
. und Compiler könnten sich list[3].x+=q;
in verwandeln, {list.Update(3, (ref int value, ref int param)=>value+=param, ref q);
aber es gibt keine solche Funktion.
list[0].X += 3;
fügt der X-Eigenschaft des ersten Elements der Liste 3 hinzu. Und list
ist eine List<Point>
und Point
ist eine Klasse mit X- und Y-Eigenschaften
Listen in .NET sind Wrapper über Arrays und verwenden ein Array intern. Die zeitliche Komplexität von Operationen an Listen ist dieselbe wie bei Arrays, jedoch ist der Aufwand mit all den zusätzlichen Funktionen / der Benutzerfreundlichkeit von Listen (z. B. der automatischen Größenänderung und den mit der Listenklasse gelieferten Methoden) etwas höher. Ich würde in jedem Fall die Verwendung von Listen empfehlen, es sei denn, es gibt einen zwingenden Grund, dies nicht zu tun, z. B. wenn Sie extrem optimierten Code schreiben müssen oder mit anderem Code arbeiten, der auf Arrays basiert.
Anstatt die Funktionen der einzelnen Datentypen zu vergleichen, ist die pragmatischste Antwort meiner Meinung nach: "Die Unterschiede sind wahrscheinlich nicht so wichtig für das, was Sie erreichen müssen, zumal beide implementiert IEnumerable
sind. Befolgen Sie daher die gängigen Konventionen und verwenden Sie a List
Bis Sie einen Grund haben, dies nicht zu tun, haben Sie wahrscheinlich Ihren Grund, ein Array über a zu verwenden List
. "
Die meiste Zeit in verwaltetem Code möchten Sie, dass Sammlungen so einfach wie möglich zu bearbeiten sind, anstatt sich über Mikrooptimierungen Gedanken zu machen.
Sie mögen unbeliebt sein, aber ich bin ein Fan von Arrays in Spielprojekten. - Die Iterationsgeschwindigkeit kann in einigen Fällen wichtig sein. Foreach auf einem Array hat erheblich weniger Overhead, wenn Sie nicht viel pro Element tun. - Das Hinzufügen und Entfernen ist mit Hilfsfunktionen nicht so schwierig. - Es ist langsamer, aber in Fällen, in denen Sie es nur einmal erstellen Es spielt möglicherweise keine Rolle. - In den meisten Fällen wird weniger zusätzlicher Speicher verschwendet (nur bei Arrays von Strukturen von großer Bedeutung). - Etwas weniger Müll und Zeiger und Zeigerjagd
Davon abgesehen verwende ich List in der Praxis weitaus häufiger als Arrays, aber sie haben jeweils ihren Platz.
Es wäre schön, wenn List einen eingebauten Typ hätte, damit sie den Wrapper- und Aufzählungsaufwand optimieren können.
Das Auffüllen einer Liste ist einfacher als ein Array. Für Arrays müssen Sie die genaue Länge der Daten kennen, für Listen kann die Datengröße jedoch beliebig sein. Außerdem können Sie eine Liste in ein Array konvertieren.
List<URLDTO> urls = new List<URLDTO>();
urls.Add(new URLDTO() {
key = "wiki",
url = "https://...",
});
urls.Add(new URLDTO()
{
key = "url",
url = "http://...",
});
urls.Add(new URLDTO()
{
key = "dir",
url = "https://...",
});
// convert a list into an array: URLDTO[]
return urls.ToArray();
Da niemand erwähnt: In C # ist ein Array eine Liste. MyClass[]
und List<MyClass>
beide implementieren IList<MyClass>
. (zB void Foo(IList<int> foo)
kann wie Foo(new[] { 1, 2, 3 })
oder genannt werden Foo(new List<int> { 1, 2, 3 })
)
Wenn Sie also eine Methode schreiben, die a List<MyClass>
als Argument akzeptiert , aber nur eine Teilmenge von Funktionen verwendet, möchten Sie diese möglicherweise aus Gründen der Benutzerfreundlichkeit als deklarieren IList<MyClass>
.
Einzelheiten:
List
, sondern implementiert nur die IList
Schnittstelle.
Dies hängt vollständig von den Kontexten ab, in denen die Datenstruktur benötigt wird. Wenn Sie beispielsweise mithilfe von List Elemente erstellen, die von anderen Funktionen oder Diensten verwendet werden sollen, ist dies der perfekte Weg, um dies zu erreichen.
Wenn Sie nun eine Liste von Elementen haben und diese nur anzeigen möchten, ist beispielsweise auf einem Webseitenarray der Container, den Sie verwenden müssen.
IEnumerable<T>
- dann kann ich Objekte streamen, anstatt sie zu puffern.
Erwähnenswert ist die Fähigkeit, vor Ort zu gießen.
interface IWork { }
class Foo : IWork { }
void Test( )
{
List<Foo> bb = new List<Foo>( );
// Error: CS0029 Cannot implicitly convert type 'System.Collections.Generic.List<Foo>' to 'System.Collections.Generic.List<IWork>'
List<IWork> cc = bb;
Foo[] bbb = new Foo[4];
// Fine
IWork[] ccc = bbb;
}
So Array bietet Bit wenig mehr Flexibilität , wenn sie in Rückgabetyp oder ein Argument für Funktionen verwendet.
IWork[] GetAllWorks( )
{
List<Foo> fooWorks = new List<Foo>( );
return fooWorks.ToArray( ); // Fine
}
void ExecuteWorks( IWork[] works ) { } // Also accept Foo[]