プログラマに強制的に定義させる基本クラスの抽象プロパティ


10

組み込みデバイスの状態パターンでコーディングしています。Stateと呼ばれる基本/抽象クラスがあり、各離散(コンクリート)状態クラスが抽象状態クラスを実装します。

Stateクラスには、いくつかの抽象メソッドがあります。ディスクリート(コンクリート)クラスに抽象メソッドを実装しない場合、Visual Studioは次のようなエラーを出します。

...エラー1 'myConcreteState'は継承された抽象メンバー 'myAbstractState'を実装していません

さて、StateNameというStateごとにStringプロパティを作成しようとしています。新しい具象クラスを作成するときはいつでも、StateNameを定義する必要があります。使用しない場合はVSでエラーをスローする必要があります。これを行う簡単な方法はありますか?

私は抽象/基本クラスでこれを試しました:

public abstract string StateName { get; set; }

ただし、各状態にGetメソッドとSetメソッドを実装する必要はありません。

改訂された質問:理想的な状況では、各Stateクラスは、StateNameを定義して抽象基本クラスから継承する必要があります。

StateName = "MyState1"; //or whatever the state's name is

そのステートメントがない場合、Visual Studioは上記のエラーを生成します。これは可能ですか?可能な場合、どのようにですか?


2
質問が理解できません。
ベンアーロンソン2015

これを行う「正しい」方法は、パラメーターとして状態名を必要とする基本クラスに保護されたコンストラクターを持つことだと思います。
Roman Reiner 2015

@RomanReiner私もそれを行うことを考えました..しかし、状態を変更/呼び出すたびに名前を入力する必要があるため、冗長であるようです。
GisMofx 2015

@BenAaronson私は質問を一番下に明確にしました。
GisMofx 2015

状態名はタイプごとに定数ですか、インスタンスごとに定数ですか?
Roman Reiner 2015年

回答:


16

これを行う「正しい」方法は、パラメーターとして状態名を必要とする基本クラスに保護されたコンストラクターを持つことだと思います。

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; } }
}

具体的な状態は、適切な名前で基本クラスコンストラクターを暗黙的に呼び出すパブリックコンストラクターを提供します。

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

基本クラスは他のコンストラクター(保護でもパブリックでもない)を公開しないため、継承する各クラスはこの単一のコンストラクターを通過する必要があり、したがって名前を定義する必要があります。

具象状態をインスタンス化するときに、コンストラクタが処理するため、名前を指定する必要がないことに注意してください。

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

1
ありがとう!実際には、私の基本クラスのコンストラクターは追加の引数をとります。2つの入力があります。これを設定するとすぐに、状態クラスコンストラクターに追加の引数が必要であるというエラーが発生し...:base(arg1, arg2)ます。これは私が探していた解決策です。これは、州のコーディングをより一貫したものにするのに役立ちます。
GisMofx 2015年

3

C#6(私は信じています-C#:新しく改良されたC#6.0)では、ゲッターのみのプロパティを作成できます。したがって、基本クラスを次のように宣言できます-

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

    // Your other functions....
}

そして、あなたのサブクラスであなたはStateそのように実装することができます-

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

またはラムダ演算子を使用してもっとすっきり-

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

どちらも常に「State_1」を返し、不変です。


1
これはpublic override string name { get; } = "State_1";、毎回値を再評価する必要がないように書くことができます。
Dave Cousineau

2

あなたの要件は矛盾しています:

StateNameというState ごとに Stringプロパティを作成しようとしています。

しかし、私は必要としないでそのすべてを実装するために、それぞれの状態。

少数のサブクラスでのみメンバーの存在を強制できる言語機能はありません。結局のところ、スーパークラスを使用するポイントは、すべてのサブクラスがスーパークラスのすべてのメンバーを(おそらくそれ以上)持つという事実に依存することです。として機能するStateが名前を持たないクラスを作成する場合、定義により、それらはのサブクラスであってはなりません(/できません)State

要件を変更するか、単純な継承以外のものを使用する必要があります。

そのままのコードで可能な解決策は、メソッドをState非抽象にして空の文字列を返すことです。


その2番目のステートメントは文脈から外れたと思いますが、明確にします。Get / Setメソッドは必要ありませんStateName = "MyState1"。単に各状態で必要です。ステートクラスにそのステートメントがない場合、理想的にはVisual Studioがエラーを生成します。
GisMofx 2015

3
@GisMofx各サブクラスで状態名を強制したい場合は、取得を抽象化しますが、状態は必要ありません。次に、各サブクラスはreturn "MyState1"実装として提供する必要があり、必要に応じて値の可変ストレージを追加できます。しかし、質問の要件を明確にする必要があります-すべてのタイプの状態は読み取り可能なStateNameを必要としますか?また、どのタイプの状態も作成後に変更する必要がありますか?
ピートカーカム2015

@PeteKirkham各状態には名前が必要です。作成後に変更しないでください。状態の名前は静的/不変です。
GisMofx 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.