it-swarm.com.de

Abstrakte Eigenschaft in der Basisklasse, um den Programmierer zu zwingen, sie zu definieren

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 Get- und Set-Methoden 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?

10
GisMofx

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.

public abstract class State
{
    private readonly string _name;

    protected State(string name)
    {
        if(String.IsNullOrEmpty(name))
            throw new ArgumentException("Must not be empty", "name");

        _name = name;
    }

    public string Name { get { return _name; } }
}

Die konkreten Zustände stellen dann einen öffentlichen Konstruktor bereit, der den Basisklassenkonstruktor implizit mit dem entsprechenden Namen aufruft.

public abstract class SomeState : State
{
    public SomeState() : base("The name of this state")
    {
        // ...
    }
}

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:

var someState = new SomeState(); // No need to define the name here
var name = someState.Name; // returns "The name of this state"
16
Roman Reiner

Ab C # 6 (ich glaube - C #: Das neue und verbesserte C # 6. ) können Sie nur Getter-Eigenschaften erstellen. Sie könnten also Ihre Basisklasse so deklarieren -

public abstract class State
{
    public abstract string name { get; }

    // Your other functions....
}

Und dann können Sie in Ihrer Unterklasse State wie folgt implementieren -

public class SomeState : State
{
    public override string name { get { return "State_1"; } }
}

Oder noch ordentlicher mit dem Lambda-Operator -

public class SomeState : State
{
    public override string name => "State_1";
}

Beide würden immer "State_1" zurückgeben und unveränderlich sein.

3
John C

Ihre Anforderungen sind ein Widerspruch:

Ich versuche, eine String-Eigenschaft für each State mit dem Namen StateName zu erstellen.

vs.

Aber ich brauche nicht, um all das in jedem Zustand zu implementieren.

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 fungieren, aber keinen Namen haben, sollten sie per Definition keine Unterklassen von State sein (/ können).

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 in State nicht abstrakt zu machen und eine leere Zeichenfolge zurückzugeben.

2
null