Bei der Planung meiner Programme beginne ich oft mit einer Gedankenkette wie folgt:
Eine Fußballmannschaft ist nur eine Liste von Fußballspielern. Deshalb sollte ich es vertreten mit:
var football_team = new List<FootballPlayer>();
Die Reihenfolge dieser Liste entspricht der Reihenfolge, in der die Spieler im Kader aufgeführt sind.
Später wird mir jedoch klar, dass Teams neben der bloßen Liste der Spieler auch andere Eigenschaften haben, die aufgezeichnet werden müssen. Zum Beispiel die laufende Punktzahl in dieser Saison, das aktuelle Budget, die einheitlichen Farben, die string
Darstellung des Teamnamens usw.
Also dann denke ich:
Okay, eine Fußballmannschaft ist wie eine Liste von Spielern, aber zusätzlich hat sie einen Namen (a
string
) und eine laufende Summe von Punkten (anint
). .NET bietet keine Klasse zum Speichern von Fußballmannschaften an, daher werde ich meine eigene Klasse erstellen. Die ähnlichste und relevanteste existierende Struktur istList<FootballPlayer>
, also werde ich davon erben:class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
Es stellt sich jedoch heraus, dass eine Richtlinie besagtList<T>
, dass Sie nicht erben sollten . Diese Richtlinie verwirrt mich in zweierlei Hinsicht.
Warum nicht?
Anscheinend List
ist irgendwie für die Leistung optimiert . Wie das? Welche Leistungsprobleme werde ich verursachen, wenn ich erweitere List
? Was genau wird brechen?
Ein weiterer Grund, den ich gesehen habe, ist, dass er List
von Microsoft bereitgestellt wird und ich keine Kontrolle darüber habe. Daher kann ich ihn später nicht mehr ändern, nachdem ich eine "öffentliche API" verfügbar gemacht habe . Aber ich habe Mühe, das zu verstehen. Was ist eine öffentliche API und warum sollte es mich interessieren? Kann ich diese Richtlinie ignorieren, wenn mein aktuelles Projekt diese öffentliche API nicht hat und wahrscheinlich nie haben wird? Welche Schwierigkeiten habe ich, wenn ich von erbe List
und es sich herausstellt, dass ich eine öffentliche API benötige?
Warum ist das überhaupt wichtig? Eine Liste ist eine Liste. Was könnte sich möglicherweise ändern? Was könnte ich möglicherweise ändern wollen?
Und wenn Microsoft nicht wollte, dass ich erbe List
, warum haben sie dann nicht die Klasse gemacht sealed
?
Was soll ich sonst noch verwenden?
Anscheinend hat Microsoft für benutzerdefinierte Sammlungen eine Collection
Klasse bereitgestellt , die anstelle von erweitert werden sollte List
. Aber diese Klasse ist sehr kahl und hat nicht viele nützliche Dinge, wieAddRange
zum Beispiel. Die Antwort von jvitor83 liefert eine Leistungsgrundlage für diese bestimmte Methode, aber wie ist eine langsame AddRange
nicht besser als nein AddRange
?
Das Erben von Collection
ist viel mehr Arbeit als das Erben von List
, und ich sehe keinen Nutzen. Sicherlich würde Microsoft mir nicht ohne Grund sagen, dass ich zusätzliche Arbeit leisten soll, daher kann ich nicht anders, als das Gefühl zu haben, etwas falsch zu verstehen, und das Erben Collection
ist eigentlich nicht die richtige Lösung für mein Problem.
Ich habe Vorschläge wie die Implementierung gesehen IList
. Einfach nein. Dies sind Dutzende von Zeilen Boilerplate-Code, die mir nichts bringen.
Schließlich schlagen einige vor, das List
in etwas einzuwickeln:
class FootballTeam
{
public List<FootballPlayer> Players;
}
Hierbei gibt es zwei Probleme:
Es macht meinen Code unnötig ausführlich. Ich muss jetzt
my_team.Players.Count
statt nur anrufenmy_team.Count
. Zum Glück kann ich mit C # Indexer definieren, um die Indizierung transparent zu machen, und alle Methoden des internen weiterleitenList
... Aber das ist viel Code! Was bekomme ich für all diese Arbeit?Es macht einfach keinen Sinn. Eine Fußballmannschaft "hat" keine Liste von Spielern. Es ist die Liste der Spieler. Sie sagen nicht "John McFootballer hat sich SomeTeams Spielern angeschlossen". Sie sagen "John ist SomeTeam beigetreten". Sie fügen "Zeichen einer Zeichenfolge" keinen Buchstaben hinzu, sondern fügen einer Zeichenfolge einen Buchstaben hinzu. Sie fügen den Büchern einer Bibliothek kein Buch hinzu, sondern fügen einer Bibliothek ein Buch hinzu.
Mir ist klar, dass das, was "unter der Haube" passiert, "X zu Ys interner Liste hinzufügen" kann, aber dies scheint eine sehr kontraintuitive Art zu sein, über die Welt zu denken.
Meine Frage (zusammengefasst)
Was ist die richtige Art und Weise C # eine Datenstruktur darstellt, die „logisch“ (das heißt, „für den menschlichen Geist“) nur ist list
der things
mit einem paar Schnickschnack?
Ist das Erben von List<T>
immer inakzeptabel? Wann ist es akzeptabel? Warum Warum nicht? Was muss ein Programmierer beachten, wenn er entscheidet, ob er erbt List<T>
oder nicht?
string
ist erforderlich, um alles zu tun, was man object
kann und mehr .