C # Generisches Überladen von ListT: Wie würde das gemacht?

8

Die StringBuilder-Klasse ermöglicht Ihnen, auf sehr intuitive Weise Methodenaufrufe an .Append (), .AppendFormat () und einige andere wie folgt zu ketten:

%Vor%

Die Methode 'List class' .Add () gibt void zurück, so dass das Verketten von Aufrufen nicht funktioniert. Dies, meiner Meinung nach, und die unsterblichen Worte von Jayne Cobb "machen einfach keinen Sinn".

Ich gebe zu, dass mein Verständnis von Generics sehr grundlegend ist, aber ich würde gerne die .Add () - Methode (und andere) überladen, so dass sie das ursprüngliche Objekt zurückgeben und Verkettung erlauben. Jede Hilfe wird mit weiteren Firefly-Zitaten belohnt.

    
Scott Baker 01.10.2010, 16:55
quelle

7 Antworten

13

Wenn Sie denselben Namen für die Methode Add beibehalten möchten, können Sie die Methode vor der Basisklasse verbergen:

%Vor%

Dies funktioniert jedoch nur, wenn Sie die Liste mit einer Variablen bearbeiten, die explizit als MyList<T> eingegeben wurde (d. h., sie funktioniert nicht, wenn Ihre Variable beispielsweise als IList<T> deklariert ist). Also denke ich, dass die Lösungen, die eine Erweiterungsmethode beinhalten, besser sind, selbst wenn das bedeutet, den Namen der Methode zu ändern.

Obwohl andere bereits Lösungen mit Erweiterungsmethoden veröffentlicht haben, ist hier noch eine, die den Vorteil hat, den tatsächlichen Typ der Sammlung zu erhalten:

%Vor%

Benutze es so:

%Vor%     
Thomas Levesque 01.10.2010, 17:07
quelle
5

use kann eine Erweiterungsmethode erstellen

%Vor%

BEARBEITEN

Wir können diese Methode auch generisch über den Sammelparameter

machen %Vor%

BEARBEITEN 2 : Vielleicht wird jemand diesen Trick nützlich finden, es ist möglich, den Initialisierer für verschachtelte Objekte und den Auflistungsinitialisierer zum Festlegen von Eigenschaften und zum Hinzufügen von Werten zu vorhandenen Instanzen zu verwenden.

%Vor%     
desco 01.10.2010 16:58
quelle
2
%Vor%

* AddItem , Append , AppendList usw. (siehe Kommentare unten)

Die gleiche Idee kam mir wie anderen auch unabhängig vor:

%Vor%

}

Und Thomas hat recht: Soweit IList<T> ICollection<T> erbt, sollten Sie ICollection verwenden.

    
abatishchev 01.10.2010 16:56
quelle
1

Lassen Sie eine Erweiterungsmethode aus:

%Vor%

Beachten Sie, dass wir es mit einem neuen Namen erstellen müssen, so als ob ein Instanzmitglied mit der Signatur übereinstimmt (dem 'Hinzufügen', über das Sie sich schon beschweren), dann wird die Erweiterungsmethode nicht aufgerufen.

Insgesamt würde ich jedoch davon abraten. Während ich mich gerne selbst verkette, ist es selten in C # -Bibliotheken, es ist nicht so idiomatisch wie in anderen Sprachen, wo es häufiger ist (kein technischer Grund dafür, obwohl einige Unterschiede in der Funktionsweise von Eigenschaften es in einigen anderen Sprachen ein bisschen mehr fördern , so wie die Dinge in Bezug auf das Gemeinsame sind). Aus diesem Grund sind die Konstrukte, die es ermöglicht, in C # nicht so vertraut wie anderswo, und Ihr Code wird wahrscheinlich von einem anderen Entwickler falsch gelesen.

    
Jon Hanna 01.10.2010 17:03
quelle
1

Sie können eine Erweiterungsmethode mit einem anderen Namen verwenden:

%Vor%

Um Code wie folgt zu erstellen:

%Vor%

Um den Namen Add beizubehalten, können Sie jedoch eine Methode wie diese verwenden:

%Vor%

Und Code wie folgt erstellen:

%Vor%

Es sieht jedoch nicht so gut aus.

Wenn wir den Typ ändern, können wir vielleicht eine bessere Syntax haben.

Gegeben diese Klasse:

%Vor%

Sie können diese Methode verwenden:

%Vor%

Und benutze Code wie folgt:

%Vor%     
Jordão 01.10.2010 17:50
quelle
1

Ich bin sicher, dass Sie diese Antwort nicht schätzen werden, aber es gibt einen sehr guten Grund, dass List & lt; & gt; .Add () auf diese Weise funktioniert. Es ist sehr schnell, es muss mit einem Array konkurrieren und weil es so eine Low-Level-Methode ist. Es ist jedoch nur ein Haar zu groß, um vom JIT-Optimierer inline gebracht zu werden. Es kann die Rückgabeanweisung nicht optimieren, die Sie benötigen, um die Listenreferenz zurückzugeben.

Schreiben von lst.Add (obj) in Ihrem Code ist kostenlos, die erste Referenz ist in einem CPU-Register verfügbar.

Eine Version von Add (), die den Verweis zurückgibt, macht den Code fast 5% langsamer. Es ist viel schlimmer für die vorgeschlagene Erweiterungsmethode, da ein ganzer zusätzlicher Stack-Frame involviert ist.

    
Hans Passant 01.10.2010 18:01
quelle
0

Ich mag den Erweiterungsansatz, den andere erwähnt haben, da er die Frage gut zu beantworten scheint (obwohl Sie ihm eine andere Methodensignatur geben müssten als das vorhandene Add ()). Es scheint auch, dass es bei solchen Aufrufen einige Inkonsistenzen bezüglich Objektrückgaben gibt (ich dachte, es wäre ein Veränderlichkeitsproblem, aber der Stringbuilder ist veränderbar, nicht wahr?), So dass Sie eine interessante Frage aufwerfen.

Ich bin jedoch neugierig, ob die AddRange-Methode nicht als fertige Lösung funktionieren würde. Gibt es einen bestimmten Grund, warum Sie die Befehle verketten möchten, anstatt alles als ein Array zu übergeben?

Würde so etwas nicht erreichen, was Sie brauchen?

%Vor%     
Steven 01.10.2010 17:23
quelle