Frage Warum nicht von List erben?


Bei der Planung meiner Programme beginne ich oft mit einer Denkkette wie folgt:

Eine Fußballmannschaft ist nur eine Liste von Fußballspielern. Daher sollte ich es darstellen mit:

var football_team = new List<FootballPlayer>();

Die Reihenfolge dieser Liste stellt die Reihenfolge dar, in der die Spieler in der Liste aufgeführt sind.

Aber ich merke später, dass Teams neben der bloßen Liste der Spieler auch noch andere Eigenschaften haben, die aufgezeichnet werden müssen. Zum Beispiel, die laufende Summe der Ergebnisse in dieser Saison, das aktuelle Budget, die einheitliche Farben, a string den Namen des Teams usw. darstellend.

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 (an int). .NET bietet keine Klasse zum Speichern von Fußballmannschaften an, daher werde ich meine eigene Klasse erstellen. Die ähnlichste und relevanteste bestehende Struktur ist List<FootballPlayer>, also werde ich davon erben:

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

Aber es stellt sich heraus, dass Eine Richtlinie sagt, dass Sie nicht von erben sollten List<T>. Ich bin von dieser Richtlinie in zweierlei Hinsicht völlig verwirrt.

Warum nicht?

Anscheinend List ist irgendwie für die Leistung optimiert. Wie das? Welche Leistungsprobleme verursache ich, wenn ich verlängere? List? Was genau wird brechen?

Ein weiterer Grund, den ich gesehen habe, ist der List wird von Microsoft zur Verfügung gestellt, und ich habe keine Kontrolle darüber Ich kann es später nicht ändern, nachdem ich eine "öffentliche API" veröffentlicht habe. Aber ich habe Mühe, das zu verstehen. Was ist eine öffentliche API und warum sollte ich mich darum kümmern? Wenn mein aktuelles Projekt diese öffentliche API nicht hat und wahrscheinlich nie haben wird, kann ich diese Richtlinie ignorieren? Wenn ich erben von List  und Es stellt sich heraus, ich brauche eine öffentliche API, welche Schwierigkeiten habe ich?

Warum ist es überhaupt wichtig? Eine Liste ist eine Liste. Was könnte sich ändern? Was könnte ich möglicherweise ändern wollen?

Und schließlich, wenn Microsoft nicht wollte, dass ich erbte ListWarum haben sie die Klasse nicht gemacht? sealed?

Was soll ich sonst noch benutzen?

Anscheinend hat Microsoft für benutzerdefinierte Sammlungen ein Collection Klasse, die statt erweitert werden sollte List. Aber diese Klasse ist sehr kahl und hat nicht viele nützliche Dinge, sowie AddRange, zum Beispiel. Antwort von jvitor83 bietet eine Performance-Begründung für diese bestimmte Methode, aber wie ist eine langsame AddRange nicht besser als nein AddRange?

Vererben von Collection ist viel mehr Arbeit als erben von Listund ich sehe keinen Nutzen. Sicher würde Microsoft mir nicht sagen, dass ich ohne Grund zusätzliche Arbeit machen soll, also kann ich nicht umhin, mich irgendwie missverstanden zu fühlen und zu erben Collection ist eigentlich nicht die richtige Lösung für mein Problem.

Ich habe Vorschläge wie die Implementierung gesehen IList. Einfach nein. Das sind Dutzende von Codezeilen, die mir nichts bringen.

Zu guter Letzt schlagen einige vor, die List in etwas:

class FootballTeam 
{ 
    public List<FootballPlayer> Players; 
}

Es gibt zwei Probleme damit:

  1. Es macht meinen Code unnötig ausführlich. Ich muss jetzt anrufen my_team.Players.Count statt nur my_team.Count. Glücklicherweise kann ich mit C # Indexer definieren, um die Indexierung transparent zu machen, und alle Methoden des internen Index weiterleiten List... Aber das ist viel Code! Was bekomme ich für all diese Arbeit?

  2. Es macht einfach keinen Sinn. Eine Fußballmannschaft "hat" keine Spielerliste. Es ist die Liste der Spieler. Du sagst nicht "John McFootballer hat sich SomeTeams Spielern angeschlossen". Sie sagen "John ist SomeTeam beigetreten". Sie fügen "Buchstaben 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 ein Buch einer Bibliothek hinzu.

Mir ist klar, dass das, was "unter der Haube" passiert, als "Hinzufügen von X zu Ys interner Liste" bezeichnet werden kann, aber dies scheint eine sehr kontraintuitive Art zu sein, über die Welt nachzudenken.

Meine Frage (zusammengefasst)

Was ist die richtige C # -Methode, um eine Datenstruktur darzustellen, die "logisch" (also "für den menschlichen Geist") ist nur a list von things mit ein paar Schnickschnack?

Erbt 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?


975
2018-02-11 03:01


Ursprung


Antworten:


Hier gibt es einige gute Antworten. Ich würde die folgenden Punkte hinzufügen.

Was ist die korrekte C # -Methode, um eine Datenstruktur darzustellen, die "logisch" (das heißt "für den menschlichen Geist") nur eine Liste von Dingen mit ein paar Schnickschnack ist?

Bitten Sie zehn Leute, die nicht mit dem Computerprogrammieren vertraut sind, die mit der Existenz des Fußballs vertraut sind, das leere Feld auszufüllen:

A football team is a particular kind of _____

Hat jemand sagen "Liste der Fußballspieler mit ein paar Schnickschnack", oder sagten sie alle "Sportmannschaft" oder "Verein" oder "Organisation"? Ihre Vorstellung, dass eine Fußballmannschaft ist eine bestimmte Art von Spielerliste ist in deinem menschlichen Verstand und in deinem menschlichen Verstand allein.

List<T> ist ein Mechanismus. Fußballmannschaft ist ein Geschäftsgegenstand Das ist ein Objekt, das ein Konzept repräsentiert, das in der Geschäftsbereich des Programms. Mischen Sie diese nicht! Eine Fußballmannschaft ist eine Art von Mannschaft; es hat ein Dienstplan, ein Dienstplan ist eine Liste von Spielern. Ein Dienstplan ist nicht ein bestimmte Art von Liste der Spieler. Ein Dienstplan ist eine Liste von Spielern. Also mach eine Eigenschaft angerufen Roster das ist ein List<Player>. Und mach es ReadOnlyList<Player> solange du dabei bist, es sei denn, du glaubst, dass jeder, der über eine Fußballmannschaft Bescheid weiß, Spieler aus dem Dienstplan streichen kann.

Erbt von List<T> immer inakzeptabel?

Inakzeptabel für wen? Mich? Nein.

Wann ist es akzeptabel?

Wenn Sie einen Mechanismus bauen, der erweitert die List<T> Mechanismus.

Was muss ein Programmierer beachten, wenn er entscheidet, ob er erbt? List<T> oder nicht?

Baue ich ein Mechanismus oder ein Geschäftsgegenstand?

Aber das ist viel Code! Was bekomme ich für all diese Arbeit?

Sie haben mehr Zeit damit verbracht, Ihre Frage zu tippen, als ob Sie die Weiterleitungsmethoden für die relevanten Mitglieder von List<T> fünfzig mal. Sie haben eindeutig keine Angst vor Ausführlichkeit, und wir sprechen hier über eine sehr kleine Menge an Code; Das ist ein paar Minuten Arbeit.

AKTUALISIEREN

Ich habe darüber nachgedacht und es gibt einen weiteren Grund, eine Fußballmannschaft nicht als Liste von Spielern zu modellieren. In der Tat könnte es eine schlechte Idee sein, eine Fußballmannschaft als zu modellieren haben eine Liste von Spielern auch. Das Problem mit einem Team als / mit einer Liste von Spielern ist, dass das, was Sie haben, ist Schnappschuss von dem Team zu einem Zeitpunkt. Ich weiß nicht, was Ihr Geschäftsfall für diesen Kurs ist, aber wenn ich eine Klasse hätte, die eine Fußballmannschaft repräsentiert, würde ich gerne Fragen stellen wie "Wie viele Seahawks-Spieler haben Spiele aufgrund einer Verletzung zwischen 2003 und 2013 verpasst?" oder "Welcher Denver-Spieler, der zuvor für ein anderes Team gespielt hat, hatte den größten Anstieg der Yards im Jahresvergleich?" oder "Sind die Piggers in diesem Jahr den ganzen Weg gegangen?"

Das heißt, eine Fußballmannschaft scheint mir gut modelliert zu sein eine Sammlung historischer Fakten wie zum Beispiel wenn ein Spieler rekrutiert wurde, verletzt, pensioniert usw. Offensichtlich ist die aktuelle Spielerliste eine wichtige Tatsache, die wahrscheinlich Front-und-Center sein sollte, aber es könnte andere interessante Dinge geben, die du mit diesem Objekt machen willst, die a erfordern mehr historische Perspektive.


1137
2018-02-11 05:43



Schließlich schlagen einige vor, die Liste in etwas zu verpacken:

Das ist der richtige Weg. "Needly wordy" ist eine schlechte Art, sich das anzuschauen. Es hat eine explizite Bedeutung beim Schreiben my_team.Players.Count. Sie möchten die Spieler zählen.

my_team.Count

..bedeutet nichts. Zählen was?

Ein Team ist keine Liste - es besteht aus mehr als nur einer Liste von Spielern. Ein Team besitzt Spieler, also sollten Spieler ein Teil davon sein (ein Mitglied).

Wenn du bist Ja wirklich Wenn Sie sich Sorgen darüber machen, dass es zu ausführlich ist, können Sie immer Eigenschaften aus dem Team herausstellen:

public int PlayerCount {
    get {
        return Players.Count;
    }
}

..die wird:

my_team.PlayerCount

Dies hat jetzt Bedeutung und hält an Das Gesetz von Demeter.

Sie sollten auch in Betracht ziehen, die Wiederverwendungsgrundsatz. Durch Erben von List<T>Du sagst ein Team ist ein Liste der Spieler und entlarvt unnötige Methoden daraus. Das ist falsch - wie Sie sagten, ist ein Team mehr als eine Liste von Spielern: Es hat einen Namen, Manager, Vorstandsmitglieder, Trainer, medizinisches Personal, Gehaltsobergrenzen, usw. Indem Sie Ihre Teamklasse eine Liste von Spielern enthalten sage "Ein Team hat ein Liste der Spieler ", aber es kann auch andere Dinge haben.


232
2018-02-11 03:05



Wow, dein Beitrag hat eine ganze Reihe von Fragen und Punkten. Die meisten Argumente, die Sie von Microsoft erhalten, sind genau richtig. Fangen wir mit allem an List<T>

  • List<T>  ist hoch optimiert. Es wird hauptsächlich als privates Mitglied eines Objekts verwendet.
  • Microsoft hat es nicht versiegelt, weil Sie manchmal eine Klasse mit einem freundlicheren Namen erstellen möchten: class MyList<T, TX> : List<CustomObject<T, Something<TX>> { ... }. Jetzt ist es so einfach wie das var list = new MyList<int, string>();.
  • CA1002: Legen Sie keine generischen Listen offen: Grundsätzlich, auch wenn Sie planen, diese App als einziger Entwickler zu verwenden, lohnt es sich, mit guten Programmierpraktiken zu entwickeln, so dass sie in Sie und Ihre zweite Natur eingeflößt werden. Sie dürfen die Liste weiterhin als anzeigen IList<T> wenn Sie einen Verbraucher benötigen, um eine indexierte Liste zu haben. Damit können Sie später die Implementierung in einer Klasse ändern.
  • Microsoft gemacht Collection<T> sehr generisch, weil es ein generisches Konzept ist ... der Name sagt alles; Es ist nur eine Sammlung. Es gibt genauere Versionen wie SortedCollection<T>, ObservableCollection<T>, ReadOnlyCollection<T>usw., die jeweils implementieren IList<T> aber nicht  List<T>.
  • Collection<T> ermöglicht das Überschreiben von Elementen (d. h. Hinzufügen, Entfernen usw.), da sie virtuell sind. List<T> nicht.
  • Der letzte Teil Ihrer Frage ist genau richtig. Ein Fußballteam ist mehr als nur eine Liste von Spielern, daher sollte es eine Klasse sein, die diese Spielerliste enthält. Denken Zusammensetzung gegen Vererbung. Eine Fußballmannschaft hat eine Liste der Spieler (ein Dienstplan), es ist keine Liste der Spieler.

Wenn ich diesen Code schreiben würde, würde die Klasse wahrscheinlich ungefähr so ​​aussehen:

public class FootballTeam
{
    // Football team rosters are generally 53 total players.
    private readonly List<T> _roster = new List<T>(53);

    public IList<T> Roster
    {
        get { return _roster; }
    }

    // Yes. I used LINQ here. This is so I don't have to worry about
    // _roster.Length vs _roster.Count vs anything else.
    public int PlayerCount
    {
        get { return _roster.Count(); }
    }

    // Any additional members you want to expose/wrap.
}

110
2018-02-11 03:26



class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal;
}

Vorheriger Code bedeutet: Ein Haufen Jungs von der Straße, die Fußball spielen, und sie haben zufällig einen Namen. Etwas wie:

People playing football

Wie auch immer, dieser Code (aus m-y's Antwort)

public class FootballTeam
{
    // Football team rosters are generally 53 total players.
    private readonly List<T> _roster = new List<T>(53);

    public IList<T> Roster
    {
        get { return _roster; }
    }

    public int PlayerCount
    {
    get { return _roster.Count(); }
    }

    // Any additional members you want to expose/wrap.
}

Bedeutet: das ist eine Fußballmannschaft, die Management, Spieler, Admins usw. hat. Etwas wie:

Image showing members (and other attributes) of the Manchester United team

So wird Ihre Logik in Bildern dargestellt ...


104
2018-02-11 15:45



Dies ist ein klassisches Beispiel für Zusammensetzung vs Erbe.

In diesem speziellen Fall:

Ist das Team eine Liste von Spielern mit zusätzlichem Verhalten?

oder

Ist das Team ein eigenes Objekt, das zufällig eine Liste von Spielern enthält?

Indem Sie List erweitern, beschränken Sie sich auf verschiedene Arten:

  1. Sie können den Zugriff nicht einschränken (z. B. können Sie verhindern, dass Personen den Dienstplan ändern). Sie erhalten alle List-Methoden, ob Sie sie alle benötigen / wollen oder nicht.

  2. Was passiert, wenn Sie auch andere Listen haben wollen? Zum Beispiel haben Mannschaften Trainer, Manager, Fans, Ausrüstung, etc. Einige von denen können durchaus eigene Listen sein.

  3. Sie beschränken Ihre Optionen für die Vererbung. Zum Beispiel möchten Sie vielleicht ein generisches Team-Objekt erstellen und dann BaseballTeam, FootballTeam usw. haben, die davon erben. Um von List zu erben, müssen Sie die Vererbung von Team durchführen, aber das bedeutet dann, dass alle verschiedenen Arten von Teams gezwungen sind, dieselbe Implementierung dieses Rosters zu haben.

Komposition - einschließlich eines Objekts, das das gewünschte Verhalten in Ihrem Objekt angibt.

Vererbung - Ihr Objekt wird zu einer Instanz des Objekts mit dem von Ihnen gewünschten Verhalten.

Beide haben ihren Nutzen, aber dies ist ein klarer Fall, in dem die Zusammensetzung vorzuziehen ist.


81
2018-02-11 10:58



Wie alle darauf hingewiesen haben, ist ein Spielerteam keine Liste von Spielern. Dieser Fehler wird von vielen Menschen überall gemacht, vielleicht auf verschiedenen Ebenen des Fachwissens. Oft ist das Problem subtil und gelegentlich sehr eklatant, wie in diesem Fall. Solche Designs sind schlecht, weil diese das verletzen Liskow-Substitutionsprinzip. Das Internet hat viele gute Artikel, die dieses Konzept erklären, z.B. http://en.wikipedia.org/wiki/Liskov_substitution_principle 


43
2018-02-11 16:56



Was ist, wenn die FootballTeam hat ein Reserven-Team zusammen mit dem Hauptteam?

class FootballTeam
{
    List<FootballPlayer> Players { get; set; }
    List<FootballPlayer> ReservePlayers { get; set; }
}

Wie würdest du das modellieren?

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

Die Beziehung ist klar hat ein und nicht ist ein.

oder RetiredPlayers?

class FootballTeam
{
    List<FootballPlayer> Players { get; set; }
    List<FootballPlayer> ReservePlayers { get; set; }
    List<FootballPlayer> RetiredPlayers { get; set; }
}

Als Faustregel sollten Sie, wenn Sie jemals von einer Sammlung erben möchten, die Klasse benennen SomethingCollection.

Tut dein SomethingCollection semantisch sinnvoll? Tun Sie das nur, wenn Sie Ihren Typ haben ist ein Sammlung von Something.

Im Falle des FootballTeam es klingt nicht richtig. EIN Team ist mehr als ein Collection. EIN Team kann Trainer, Trainer, etc. haben, wie die anderen Antworten darauf hingewiesen haben.

FootballCollection klingt wie eine Sammlung von Fußbällen oder vielleicht eine Sammlung von Fußballutensilien. TeamCollection, eine Sammlung von Teams.

FootballPlayerCollection klingt wie eine Sammlung von Spielern, die ein gültiger Name für eine Klasse wäre, von der er erbt List<FootballPlayer> wenn du das wirklich willst.

Ja wirklich List<FootballPlayer> ist eine perfekte Art, mit der man sich auseinandersetzen muss. Könnte sein IList<FootballPlayer> wenn Sie es von einer Methode zurückgeben.

Zusammenfassend

Frag dich selbst

  1. Ist  X ein Y? oder Hat  X ein Y?

  2. Bedeutet mein Klassenname was sie sind?


34
2018-02-12 11:41



Vor allem geht es um Usability. Wenn Sie die Vererbung verwenden, wird die Team Die Klasse stellt das Verhalten (Methoden) zur Verfügung, das ausschließlich für die Manipulation von Objekten entwickelt wurde. Beispielsweise, AsReadOnly() oder CopyTo(obj) Methoden ergeben für das Teamobjekt keinen Sinn. Anstatt der AddRange(items) Methode würden Sie wahrscheinlich eine beschreibende möchten AddPlayers(players) Methode.

Wenn Sie LINQ verwenden möchten, implementieren Sie eine generische Schnittstelle wie z ICollection<T> oder IEnumerable<T> würde mehr Sinn machen.

Wie gesagt, die Komposition ist der richtige Weg. Implementiere einfach eine Liste von Spielern als private Variable.


27
2018-02-11 03:25



Design> Implementierung

Welche Methoden und Eigenschaften Sie bereitstellen, ist eine Designentscheidung. Welche Basisklasse Sie erben, ist ein Implementierungsdetail. Ich denke, es lohnt sich, einen Schritt zurück zu Ersterem zu machen.

Ein Objekt ist eine Sammlung von Daten und Verhalten.

Ihre ersten Fragen sollten also lauten:

  • Welche Daten umfasst dieses Objekt in dem Modell, das ich erstelle?
  • Welches Verhalten zeigt dieses Objekt in diesem Modell?
  • Wie könnte sich das in Zukunft ändern?

Denken Sie daran, dass Vererbung eine "isa" (ist ein) Beziehung impliziert, während Zusammensetzung eine "hat eine" (hasa) Beziehung impliziert. Wählen Sie aus Ihrer Sicht den für Ihre Situation richtigen aus und berücksichtigen Sie dabei, wo sich die Dinge entwickeln könnten, wenn sich Ihre Anwendung weiterentwickelt.

Denken Sie über Schnittstellen nach, bevor Sie in konkreten Typen denken, da es manchen Leuten leichter fällt, ihr Gehirn so in den "Design-Modus" zu versetzen.

Dies ist nicht etwas, was jeder bewusst auf dieser Ebene im täglichen Schreiben tut. Aber wenn Sie über so ein Thema nachdenken, treten Sie in Designgewässer ein. Sich dessen bewusst zu sein, kann befreiend sein.

Berücksichtigen Sie Entwurfsmerkmale

Sehen Sie sich List <T> und IList <T> in MSDN oder Visual Studio an. Sehen Sie, welche Methoden und Eigenschaften sie bereitstellen. Sehen diese Methoden alle so aus, als würde jemand aus Ihrer Sicht mit einem FootballTeam zu tun haben?

Ist footballTeam.Reverse () für Sie sinnvoll? Ist footballTeam.ConvertAll <TOutput> () wie etwas, das Sie wollen?

Dies ist keine Trickfrage. die Antwort könnte wirklich "ja" sein. Wenn Sie List <Player> oder IList <Player> implementieren / erben, bleiben Sie bei ihnen hängen. Wenn das für Ihr Modell ideal ist, tun Sie es.

Wenn Sie ja entscheiden, ist das sinnvoll, und Sie möchten, dass Ihr Objekt als Sammlung / Liste von Spielern (Verhalten) behandelbar ist, und Sie ICollection oder IList daher unbedingt implementieren möchten. Notionally:

class FootballTeam : ... ICollection<Player>
{
    ...
}

Wenn Sie möchten, dass Ihr Objekt eine Sammlung / Liste von Spielern (Daten) enthält und Sie möchten, dass die Sammlung oder Liste eine Eigenschaft oder ein Mitglied ist, tun Sie dies auf jeden Fall. Notionally:

class FootballTeam ...
{
    public ICollection<Player> Players { get { ... } }
}

Sie möchten vielleicht, dass die Personen nur die Menge der Spieler aufzählen können, anstatt sie zu zählen, hinzuzufügen oder zu entfernen. IEnumerable <Player> ist eine perfekt zu berücksichtigende Option.

Sie haben vielleicht das Gefühl, dass keine dieser Schnittstellen in Ihrem Modell überhaupt nützlich ist. Dies ist weniger wahrscheinlich (IEnumerable <T> ist in vielen Situationen nützlich), aber es ist immer noch möglich.

Jeder, der versucht, Ihnen zu sagen, dass einer von ihnen kategorisch und definitiv ist falsch in jedem Fall ist fehlgeleitet. Wer versucht, es Ihnen zu sagen, ist kategorisch und endgültig Recht in jedem Fall ist fehlgeleitet.

Weiter zu Implementierung

Sobald Sie sich für Daten und Verhalten entschieden haben, können Sie eine Entscheidung über die Implementierung treffen. Dies beinhaltet, auf welche konkreten Klassen Sie durch Vererbung oder Komposition angewiesen sind.

Dies ist vielleicht kein großer Schritt, und die Leute verschmelzen oft Design und Implementierung, da es durchaus möglich ist, in einem oder zwei Sekunden alles durchzugehen und anzufangen fortzuschreiten.

Ein Gedankenexperiment

Ein künstliches Beispiel: Wie andere schon erwähnt haben, ist ein Team nicht immer "nur" eine Ansammlung von Spielern. Behalten Sie eine Sammlung von Match-Scores für das Team bei? Ist das Team in Ihrem Modell mit dem Club austauschbar? Wenn ja, und wenn Ihr Team eine Sammlung von Spielern ist, ist es vielleicht auch eine Sammlung von Mitarbeitern und / oder eine Sammlung von Punkten. Dann enden Sie mit:

class FootballTeam : ... ICollection<Player>, 
                         ICollection<StaffMember>,
                         ICollection<Score>
{
    ....
}

Ungeachtet des Entwurfs können Sie zu diesem Zeitpunkt in C # nicht alle implementieren, indem Sie ohnehin List <T> erben, da C # "nur" die Einzelvererbung unterstützt. (Wenn Sie diesen Malakkus in C ++ ausprobiert haben, können Sie dies als eine gute Sache betrachten.) Es ist wahrscheinlich, dass eine Sammlung über Vererbung und eine über Komposition implementiert wird Gefühl dreckig. Und Eigenschaften wie Count werden für Benutzer verwirrend, es sei denn, Sie implementieren ILIst <Player> .Count und IList <StaffMember> .Count usw. explizit, und dann sind sie eher schmerzhaft als verwirrend. Sie können sehen, wohin das geht; Bauchgefühl beim Nachdenken über diesen Weg kann Ihnen gut sagen, dass es sich falsch anfühlt, in diese Richtung zu gehen (und zu Recht oder Unrecht, Ihre Kollegen könnten es auch, wenn Sie es so umsetzen!)

Die kurze Antwort (zu spät)

Die Richtlinie zum Nicht-Erben von Auflistungsklassen ist nicht C # -spezifisch, Sie finden sie in vielen Programmiersprachen. Es ist Weisheit, kein Gesetz. Ein Grund dafür ist, dass sich in der Praxis die Zusammensetzung häufig durch Vererbung in Bezug auf Verständlichkeit, Umsetzbarkeit und Wartbarkeit auszeichnet. Es ist häufiger bei realen Welt- / Domänenobjekten, nützliche und konsistente "Hasa" -Beziehungen als nützliche und konsistente "isa" -Beziehungen zu finden, es sei denn, Sie sind tief im Abstrakt, vor allem mit der Zeit und den genauen Daten und Verhalten von Objekten im Code Änderungen. Dies sollte nicht dazu führen, dass Sie immer das Erben von Auflistungsklassen ausschließen; aber es kann suggestiv sein.


25
2018-02-11 22:27



Eine Fußballmannschaft ist nicht eine Liste von Fußballspielern. Eine Fußballmannschaft besteht aus eine Liste von Fußballspielern!

Das ist logisch falsch:

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

und das ist richtig:

class FootballTeam 
{ 
    public List<FootballPlayer> players
    public string TeamName; 
    public int RunningTotal 
}

23
2018-02-11 16:25