Heute war ich überrascht, dass ich in C # Folgendes tun kann:
List<int> a = new List<int> { 1, 2, 3 };
Warum kann ich das tun? Welcher Konstruktor heißt? Wie kann ich das mit meinen eigenen Klassen machen? Ich weiß, dass dies der Weg ist, um Arrays zu initialisieren, aber Arrays sind Sprachelemente und Listen sind einfache Objekte ...
c#
.net
list
initialization
Ignacio Soler Garcia
quelle
quelle
{ { "key1", "value1"}, { "key2", "value2"} }
List<int>
tatsächlich nur ein Array ist. Ich hasse das C # -Team dafür, dass sie es nicht benennen,ArrayList<T>
was so offensichtlich und natürlich klingt.Antworten:
Dies ist Teil der Syntax der Auflistungsinitialisierung in .NET. Sie können diese Syntax für jede Sammlung verwenden, die Sie erstellen, solange:
Es implementiert
IEnumerable
(vorzugsweiseIEnumerable<T>
)Es hat eine Methode namens
Add(...)
Was passiert, ist, dass der Standardkonstruktor aufgerufen wird und dann
Add(...)
für jedes Mitglied des Initialisierers aufgerufen wird.Somit sind diese beiden Blöcke ungefähr identisch:
Und
Sie können einen alternativen Konstruktor aufrufen, wenn Sie möchten, um beispielsweise eine Überdimensionierung
List<T>
während des Wachstums zu vermeiden usw.:Beachten Sie, dass die
Add()
Methode kein einzelnes Element annehmen muss, z. B. dieAdd()
Methode fürDictionary<TKey, TValue>
zwei Elemente:Ist ungefähr identisch mit:
Um dies zu Ihrer eigenen Klasse hinzuzufügen, müssen Sie, wie erwähnt, lediglich
IEnumerable
(vorzugsweiseIEnumerable<T>
) implementieren und eine oder mehrereAdd()
Methoden erstellen :Dann können Sie es genau wie die BCL-Sammlungen verwenden:
(Weitere Informationen finden Sie im MSDN. )
quelle
List<int> temp = new List<int>(); temp.Add(1); ... List<int> a = temp;
Das heißt, diea
Variable wird erst initialisiert, nachdem alle Adds aufgerufen wurden. Andernfalls wäre es legal, so etwas zu tun,List<int> a = new List<int>() { a.Count, a.Count, a.Count };
was eine verrückte Sache ist.List<int> a; a = new List<int>() { a.Count };
undList<int> a = new List<int>() { a.Count };
T x = y;
dasselbe ist wieT x; x = y;
: Diese Tatsache kann zu einigen merkwürdigen Situationen führen. Zum Beispielint x = M(out x) + x;
ist vollkommen legal, weilint x; x = M(out x) + x;
es legal ist.IEnumerable<T>
; Das Nicht-GenerischeIEnumerable
reicht aus, um die Verwendung der Syntax des Collection-Initialisierers zu ermöglichen.using (var x = new Something{ 1, 2 })
Das Objekt wird nicht entsorgt, wenn einer derAdd
Aufrufe fehlschlägt.Es ist so genannter syntaktischer Zucker .
List<T>
ist die "einfache" Klasse, aber der Compiler behandelt sie speziell, um Ihnen das Leben zu erleichtern.Dieser wird als Sammlungsinitialisierer bezeichnet . Sie müssen implementieren
IEnumerable<T>
undAdd
methodisieren.quelle
Gemäß der C # Version 3.0-Spezifikation "Das Auflistungsobjekt, auf das ein Auflistungsinitialisierer angewendet wird, muss von einem Typ sein, der System.Collections.Generic.ICollection für genau ein T implementiert."
Diese Informationen scheinen jedoch zum Zeitpunkt dieses Schreibens ungenau zu sein. siehe Eric Lipperts Klarstellung in den Kommentaren unten.
quelle
Es funktioniert dank Sammlungsinitialisierern , für die die Sammlung grundsätzlich eine Add-Methode implementieren muss, und die die Arbeit für Sie erledigt.
quelle
Eine weitere coole Sache bei Sammlungsinitialisierern ist, dass Sie mehrere
Add
Methodenüberladungen haben und sie alle im selben Initialisierer aufrufen können! Zum Beispiel funktioniert dies:Es ruft die richtigen Überladungen auf. Außerdem sucht es nur nach der Methode mit dem Namen
Add
, der Rückgabetyp kann alles sein.quelle
Die Array-ähnliche Syntax wird in einer Reihe von
Add()
Aufrufen gedreht.Um dies in einem viel interessanteren Beispiel zu sehen, betrachten Sie den folgenden Code, in dem ich zwei interessante Dinge tue, die in C # zuerst illegal klingen: 1) Festlegen einer schreibgeschützten Eigenschaft, 2) Festlegen einer Liste mit einem Array wie dem Initialisierer.
Dieser Code funktioniert einwandfrei, obwohl 1) MyList schreibgeschützt ist und 2) ich eine Liste mit Array-Initialisierer erstellt habe.
Der Grund, warum dies funktioniert, liegt darin, dass der Compiler in Code, der Teil eines Objektinitialisierers ist, eine
{}
ähnliche Syntax immer in eine Reihe vonAdd()
Aufrufen umwandelt, die selbst in einem schreibgeschützten Feld vollkommen legal sind.quelle