web-dev-qa-db-ja.com

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

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

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

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

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

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

public abstract string StateName { get; set; }

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

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

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

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

10
GisMofx

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

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"
16
Roman Reiner

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

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」を返し、不変です。

3
John C

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

each StateというStateNameという文字列プロパティを作成しようとしています。

vs.

しかし、私は不要すべてをeach Stateに実装します。

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

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

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

2
null