Erweitern einer Aufzählung durch Vererbung

Lesezeit: 8 Minuten

Erweitern einer Aufzahlung durch Vererbung
bald

Ich weiß, dass dies eher gegen die Idee von Aufzählungen verstößt, aber ist es möglich, Aufzählungen in C#/Java zu erweitern? Ich meine “erweitern” sowohl im Sinne des Hinzufügens neuer Werte zu einer Aufzählung, als auch im OO-Sinne des Erbens von einer bestehenden Aufzählung.

Ich gehe davon aus, dass dies in Java nicht möglich ist, da es sie erst vor relativ kurzer Zeit erhalten hat (Java 5?). C# scheint jedoch Leuten, die verrückte Dinge tun wollen, nachsichtiger zu sein, also dachte ich, dass es irgendwie möglich sein könnte. Vermutlich könnte es durch Reflektion gehackt werden (nicht, dass Sie diese Methode tatsächlich verwenden würden)?

Ich bin nicht unbedingt daran interessiert, eine bestimmte Methode zu implementieren, es hat nur meine Neugier geweckt, als es mir einfiel 🙂

  • Beantwortet das deine Frage? Enum “Vererbung”

    – T. Todua

    30. Oktober 2019 um 17:02 Uhr

Der Grund, warum Sie Enums nicht erweitern können, liegt darin, dass dies zu Problemen mit Polymorphismus führen würde.

Angenommen, Sie haben eine Aufzählung MyEnum mit den Werten A, B und C und erweitern sie mit dem Wert D als MyExtEnum.

Angenommen, eine Methode erwartet irgendwo einen myEnum-Wert, beispielsweise als Parameter. Es sollte legal sein, einen MyExtEnum-Wert anzugeben, da es sich um einen Untertyp handelt, aber was werden Sie jetzt tun, wenn sich herausstellt, dass der Wert D ist?

Um dieses Problem zu beseitigen, ist das Erweitern von Aufzählungen illegal

  • Eigentlich ist der Grund einfach, dass es keinen Sinn macht. Das von Ihnen erwähnte Problem, dh der Client-Code erhält eine Konstante, die er nicht erwartet, besteht bei der aktuellen Implementierung immer noch – tatsächlich lässt Sie der Compiler nicht zu switch auf Enum-Werte ohne Angabe von a default case oder das Auslösen einer Ausnahme. Und selbst wenn dies der Fall wäre, könnte die Enum zur Laufzeit aus einer separaten Kompilierung stammen

    – Raffaele

    2. Mai 2014 um 10:37 Uhr

  • @Raffaele Ich habe das gerade ausprobiert, und zumindest in Java 7 können Sie eine Aufzählung ohne a einschalten default Fall oder Werfen.

    – Datan

    6. Mai 2014 um 17:38 Uhr

  • @Dathan du hast definitiv recht! Wie es geschrieben steht, ist das einfach falsch – vielleicht sollte ich es entfernen? Ich dachte an den Fall, wenn Sie a verwenden switch um einen erforderlichen Wert bereitzustellen, z. B. den Anfangsbuchstaben eines Ortsnamens oder to return

    – Raffaele

    6. Mai 2014 um 18:18 Uhr

  • Das ist nichts Persönliches, Rik. Aber das ist so ziemlich der schlimmste Grund überhaupt! Polymorphismus und Aufzählung … DayOfWeek a = (DayOfWeek) 1; DayOfWeek b = (DayOfWeek) 4711; Console.WriteLine(a + ", " + b);

    – Bitter blau

    15. April 2015 um 12:16 Uhr


Erweitern einer Aufzahlung durch Vererbung
Zimon

Wenn integrierte Aufzählungen nicht ausreichen, können Sie es auf die altmodische Weise tun und Ihre eigenen erstellen. Wenn Sie beispielsweise eine zusätzliche Eigenschaft hinzufügen möchten, z. B. ein Beschreibungsfeld, können Sie dies wie folgt tun:

public class Action {
    public string Name {get; private set;}
    public string Description {get; private set;}

    private Action(string name, string description) {
        Name = name;
        Description = description;
    }

    public static Action DoIt = new Action("Do it", "This does things");
    public static Action StopIt = new Action("Stop It", "This stops things");
}

Sie können es dann wie eine Aufzählung behandeln:

public void ProcessAction(Action a) {
    Console.WriteLine("Performing action: " + a.Name)
    if (a == Action.DoIt) {
       // ... and so on
    }
}

Der Trick besteht darin, sicherzustellen, dass der Konstruktor privat ist (oder geschützt ist, wenn Sie erben möchten) und dass Ihre Instanzen statisch sind.

  • Ich bin kein C#-Mensch, aber möchten Sie nicht ein bisschen final (oder seal/const/whatever) drin haben?

    – Tom Hawtin – Angelleine

    11. September 2008 um 12:29 Uhr

  • Ich glaube nicht. Oder zumindest nicht für die Situation, in der Sie von dieser Klasse erben möchten, um neue „enum“-Werte hinzuzufügen. Endgültig und versiegelt verhindern die Vererbung IIRC.

    – gleich

    11. September 2008 um 19:50 Uhr

  • @alastairs Ich glaube, er meinte hinzufügen final zum public static Action DoIt = new Action("Do it", "This does things"); Linie, nicht die Klasse.

    – zerkleinern

    13. August 2014 um 19:09 Uhr

  • Wie in durch Hinzufügen readonlyäh: public static readonly Action DoIt = new Action("Do it", "This does things");

    – ErikE

    20. Juli 2015 um 20:43 Uhr

Sie gehen in die falsche Richtung: Eine Unterklasse einer Aufzählung hätte weniger Einträge.

Denken Sie in Pseudocode:

enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat };  // (not valid C#)

Jede Methode, die ein Tier akzeptieren kann, sollte ein Säugetier akzeptieren können, aber nicht umgekehrt. Subclassing dient dazu, etwas spezifischer zu machen, nicht allgemeiner. Deshalb ist “Objekt” die Wurzel der Klassenhierarchie. Wenn Aufzählungen vererbbar wären, hätte eine hypothetische Wurzel der Aufzählungshierarchie jedes mögliche Symbol.

Aber nein, C#/Java erlaubt keine Unteraufzählungen, AFAICT, obwohl es manchmal wirklich nützlich wäre. Das liegt wahrscheinlich daran, dass sie sich dafür entschieden haben, Enums als Ints (wie C) anstelle von internierten Symbolen (wie Lisp) zu implementieren. (Oben, was stellt (Tier)1 dar und was stellt (Säugetier)1 dar, und haben sie denselben Wert?)

Sie könnten jedoch Ihre eigene enum-ähnliche Klasse (mit einem anderen Namen) schreiben, die dies bereitstellt. Mit C#-Attributen sieht es vielleicht sogar nett aus.

  • interessante Analyse. hab so noch nie drüber nachgedacht!

    – Abbas Gadhia

    11. November 2012 um 16:59 Uhr

  • Interessant, aber meiner Meinung nach falsch. Zu implizieren, dass es weniger Typen in einer Unterklasse geben sollte, ist in Bezug auf Tierklassifikationsbäume sinnvoll, aber nicht in Bezug auf den Code. Wenn Sie Code sublcassieren, gibt es nie weniger Methoden. Es gibt nie weniger Mitgliedsvariablen. Ihr Argument scheint für Software nicht so zu gelten wie für Tierklassifikationen.

    – Kieveli

    11. März 2013 um 13:48 Uhr

  • @Kieveli, deine Analyse ist falsch. Das Hinzufügen eines Mitglieds hat nicht dieselbe Auswirkung auf ein Objekt wie das Hinzufügen zu der Menge seiner möglichen Werte. Das hat sich Ken nicht ausgedacht; Es gibt klare und präzise Regeln der Informatik, die erklären, warum sie so funktioniert. Versuchen Sie, nach Kovarianz und Kontravarianz zu suchen (nicht nur akademische Masturbation, es hilft Ihnen, Regeln für Dinge wie Funktionssignaturen und Container zu verstehen).

    – jwg

    27. März 2013 um 17:04 Uhr

  • @Kieveli Angenommen, Sie hätten eine ‘StreamWriter’-Klasse (nimmt Stream – schreibt Stream). Sie würden ‘TextWriter : StreamWriter’ erstellen (nimmt Stream – schreibt Text). Jetzt erstellen Sie ‘HtmlWriter : TextWriter’ (nimmt Stream – schreibt hübsches HTML). Jetzt hat der HtmlWriter offensichtlich mehr Mitglieder, Methoden und so weiter. Versuchen Sie jetzt, einen Stream von einer Soundkarte zu nehmen und ihn mit HtmlWriter in eine Datei zu schreiben 🙂

    – vertriebener Lärm

    7. September 2016 um 10:30 Uhr

  • Dieses Beispiel ist erfunden und beweist nicht, dass es in der erweiterten Klasse niemals MEHR Aufzählungswerte geben sollte. enum VehicalParts {Lizenz, Geschwindigkeit, Kapazität}; enum CarParts{Lenkrad, Windschutzscheibe}; +alles was Vehical auch hat

    – Bernoulli-Eidechse

    28. Februar 2020 um 19:21 Uhr

Aufzählungen sollen die Aufzählung aller möglichen Werte darstellen, daher widerspricht das Erweitern eher der Idee.

Was Sie jedoch in Java (und vermutlich C++0x) tun können, ist eine Schnittstelle anstelle einer Aufzählungsklasse. Setzen Sie dann Ihre Standardwerte in eine Aufzählung, die die Funktion implementiert. Offensichtlich können Sie java.util.EnumSet und dergleichen nicht verwenden. Dies ist der Ansatz, der in “mehr NIO-Funktionen” verfolgt wird, die in JDK7 enthalten sein sollten.

public interface Result {
    String name();
    String toString();
}
public enum StandardResults implements Result {
    TRUE, FALSE
}


public enum WTFResults implements Result {
    FILE_NOT_FOUND
}

Sie können die .NET-Reflektion verwenden, um die Beschriftungen und Werte zur Laufzeit aus einer vorhandenen Aufzählung abzurufen (Enum.GetNames() und Enum.GetValues() sind die beiden spezifischen Methoden, die Sie verwenden würden) und verwenden Sie dann die Code-Injektion, um eine neue mit diesen Elementen und einigen neuen zu erstellen. Dies scheint etwas analog zu “Erben von einer vorhandenen Aufzählung” zu sein.

Erweitern einer Aufzahlung durch Vererbung
Darrell Denlinger

Ich habe niemanden gesehen, der dies erwähnt hat, aber der Ordinalwert einer Aufzählung ist wichtig. Wenn Sie beispielsweise mit Grails eine Aufzählung in der Datenbank speichern, verwendet sie den Ordinalwert. Wenn Sie eine Aufzählung irgendwie erweitern könnten, was wären die Ordnungswerte Ihrer Erweiterungen? Wenn Sie es an mehreren Stellen erweitern, wie könnten Sie diese Ordnungszahlen irgendwie ordnen? Chaos/Instabilität in den Ordinalwerten wäre eine schlechte Sache, was wahrscheinlich ein weiterer Grund ist, warum die Sprachdesigner dies nicht berührt haben.

Eine weitere Schwierigkeit, wenn Sie der Sprachdesigner wären, wie können Sie die Funktionalität der Methode values() beibehalten, die alle Enum-Werte zurückgeben soll. Wofür würden Sie das aufrufen und wie würde es alle Werte erfassen?

1647175631 913 Erweitern einer Aufzahlung durch Vererbung
Oskar

Das Hinzufügen von Aufzählungen ist eine ziemlich übliche Sache, wenn Sie zum Quellcode zurückkehren und ihn bearbeiten, jede andere Methode (Vererbung oder Reflektion, falls beides möglich ist) wird wahrscheinlich zurückkommen und Sie treffen, wenn Sie ein Upgrade der Bibliothek und erhalten Sie haben den gleichen Aufzählungsnamen eingeführt oder der gleiche Enum-Wert – Ich habe viel Lowlevel-Code gesehen, bei dem die Ganzzahl mit der binären Codierung übereinstimmt, bei der Sie auf Probleme stoßen würden

Idealerweise sollte Code, der Aufzählungen referenziert, nur als Gleichheit (oder Schalter) geschrieben werden, und versuchen Sie, zukunftssicher zu sein, indem Sie nicht erwarten, dass die Aufzählungsmenge konstant ist

997660cookie-checkErweitern einer Aufzählung durch Vererbung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy