Ich codiere mit einem Statusmuster für ein eingebettetes Gerät. Ich habe eine Basis- / abstrakte Klasse namens State und dann implementiert jede diskrete (konkrete) Zustandsklasse die abstrakte Zustandsklasse.
In der Staatsklasse habe ich mehrere abstrakte Methoden. Wenn ich die abstrakten Methoden nicht in der diskreten (konkreten) Klasse implementiere, gibt Visual Studio einen Fehler wie den folgenden aus:
... Fehler 1 'myConcreteState' implementiert kein geerbtes abstraktes Mitglied 'myAbstractState'
Jetzt: Ich versuche, für jeden Status eine String-Eigenschaft namens StateName zu erstellen. Immer wenn ich eine neue konkrete Klasse erstelle, muss ich StateName definieren. Ich möchte, dass VS einen Fehler auslöst, wenn ich ihn nicht verwende. Gibt es eine einfache Möglichkeit, dies zu tun?
Ich habe dies in der abstrakten / Basisklasse versucht:
public abstract string StateName { get; set; }
Ich muss die Methoden Get und Set jedoch nicht in jedem Status implementieren.
Überarbeitete Frage: In einer idealen Situation müsste für jede Statusklasse StateName definiert und von der abstrakten Basisklasse geerbt werden.
StateName = "MyState1"; //or whatever the state's name is
Wenn diese Anweisung fehlt, generiert Visual Studio einen Fehler wie oben beschrieben. Ist das möglich und wenn ja, wie?
Antworten:
Ich denke, der "richtige" Weg, dies zu tun, besteht darin, einen geschützten Konstruktor für die Basisklasse zu haben, der den Statusnamen als Parameter benötigt.
Die konkreten Zustände stellen dann einen öffentlichen Konstruktor bereit, der den Basisklassenkonstruktor implizit mit dem entsprechenden Namen aufruft.
Da die Basisklasse keine anderen Konstruktoren (weder geschützt noch öffentlich) verfügbar macht, muss jede erbende Klasse diesen einzelnen Konstruktor durchlaufen und daher einen Namen definieren.
Beachten Sie, dass Sie den Namen nicht angeben müssen, wenn Sie einen konkreten Status instanziieren, da der Konstruktor dies übernimmt:
quelle
...:base(arg1, arg2)
! Dies ist eine Lösung, nach der ich gesucht habe. Dies hilft wirklich dabei, meine Statuscodierung konsistenter zu halten.Ab C # 6 (ich glaube - C #: Das neue und verbesserte C # 6.0 ) können Sie nur Getter-Eigenschaften erstellen. Sie könnten also Ihre Basisklasse so deklarieren -
Und dann können Sie in Ihrer Unterklasse so implementieren
State
-Oder noch ordentlicher mit dem Lambda-Operator -
Beide würden immer "State_1" zurückgeben und unveränderlich sein.
quelle
public override string name { get; } = "State_1";
wodurch der Wert nicht jedes Mal neu bewertet werden muss.Ihre Anforderungen sind ein Widerspruch:
vs.
Es gibt keine Sprachfunktion, mit der Sie die Existenz eines Mitglieds in nur wenigen Unterklassen erzwingen können. Schließlich besteht der Sinn der Verwendung einer Superklasse darin, sich auf die Tatsache zu verlassen, dass alle Unterklassen alle Mitglieder der Superklasse (und möglicherweise mehr) haben. Wenn Sie Klassen erstellen möchten, die als
State
solche fungieren, aber keinen Namen haben, sollten sie per Definition keine Unterklassen von sein (/ können)State
.Sie müssen entweder Ihre Anforderungen ändern oder etwas anderes als einfache Vererbung verwenden.
Eine mögliche Lösung mit dem Code könnte darin bestehen, die Methode
State
nicht abstrakt zu machen und eine leere Zeichenfolge zurückzugeben.quelle
StateName = "MyState1"
in jedem Zustand. Wenn ich diese Anweisung nicht in der Statusklasse habe, generiert Visual Studio im Idealfall einen Fehler.return "MyState1"
als Implementierung bereitstellen und kann bei Bedarf veränderlichen Speicher für den Wert hinzufügen. Sie müssen jedoch die Anforderungen in der Frage klarstellen: Erfordert jeder Zustandstyp einen lesbaren Statusnamen und muss er nach der Erstellung mutiert werden?