2017-07-19 11 views
4

私は現在ツアー用のソフトウェアプログラムを作成しており、展示品で構成されています。展示物は、任意の時点で、ExhibitStates列挙型で定義された四つの状態、のいずれかにされています。展示を設定します開発者のためにC#で公開列挙値を制限することはできますか?

private enum ExhibitState { Ready, Active, Complete, Inactive }; 

、私はそれらをしたい2つだけ、「開始」の状態が存在します中から選択できるようにする:現在

public enum StartingExhibitState { Ready, Inactive }; 

、私はそれが初期化されるとなるように設定している、展示はすぐにそうように、その開始状態に合わせて、その状態を設定します:

 switch (startingState) { 
      case StartingExhibitState.Ready: 
       SetState(ExhibitState.Ready); 
       break; 
      case StartingExhibitState.Inactive: 
       SetState(ExhibitState.Inactive); 
       break; 
     } 

これがベストプラクティスだったかどうか、私は今日疑問に思いました。どのenumオプションがpublicかprivateかを制限する良い方法はありますか?または、単に2つの別々の列挙型を持つのが最善でしょうか?

ありがとうございました。

+0

あなたのクラスのenum値の "設定"を制限する方が簡単ではないでしょうか? – maccettura

+0

switchステートメントの設定方法は、単にステートを一度に設定したり、使用したくないケースを設定したり、一度に中断したり、デフォルトアクションでステートを設定したりすることができます。私は、状態が本当に非アクティブから完全に切り替えることができるかどうかという論理もあると思います。 – Icepickle

+3

デフォルトでは 'Inactive'になり、' SetReady'メソッドを提供して、開始状態をまったく渡す必要がなくなります。 –

答えて

4

あなたは、第二の列挙型を作成した場合 - あなたの意図は非常に明確にする方法

public enum ExhibitState 
{ 
    Inactive = 0, 
    Active = 1, 
    Ready = 2, 
    Complete = 3 
}; 

public enum InitialStates 
{ 
    Inactive = ExhibitState.Inactive, 
    Ready = ExhibitState.Ready 
}; 

public void SetInitial(InitialStates state) 
{ 
    SetState((ExhibitState)state); 
} 

を設定する署名を通じて説明するあなたはさらに行く場合は、メソッドに渡す間違った値を防止するためのコンパイラのヘルプを追加することができます。

public sealed class InitialState 
{ 
    public static readonly InitialState Initial = new InitialState(ExhibitState.Initial); 

    public static readonly InitialState Ready = new InitialState(ExhibitState.Ready); 

    public ExhibitState State { get; }    

    private InitialState(ExhibitState state) 
    { 
     State = state; 
    } 
} 

コンストラクタをprivateから除外して、他の場所からクラスをインスタンス化しないようにしました。
クラスの導出および変更を防止するために、sealedとマークされたクラス。あなたはInitialStateクラスのコードを変更するまで

次に、あなたの方法は、他の

public void SetInitial(InitialState start) 
{ 
    SetState(start.State); 
} 

// use it 
SetInitial(InitialState.Initial); 
SetInitial(InitialState.Ready); 

何も渡されないことができないようになります。

+1

あなたのenum値が一致しません。 public Enum InitialStates {Ready、Inactive = 3};を宣言する必要があります。そうでなければ、 'InitialStates.Inactive'は' ExhibitState.Active'にマップされます。 –

+5

あなたは明示できます: 'public enum InitialStates {Ready = ExhibitState.Ready、Inactive = ExhibitState.Inactive};' –

+0

これは私が現在やっていることです。私はそれが最善のアプローチか、それとももっと単純なものがあるのか​​疑問に思いました。私はこれが行く方法だと思います。ありがとうございます – SemperCallide

2

は、代わりに列挙型(それらのか、2)を使用して、あなたは、クラスベースのアプローチを使用することができます。

public abstract class ExhibitState 
{ 
    public static ExhibitInitialState Ready { get { return new ExhibitReadyState(); } } 
    public static ExhibitInitialState Inactive { get { return new ExhibitInactiveState(); } } 
    public static ExhibitState Complete { get { return new ExhibitCompleteState(); } } 
    public static ExhibitState Active { get { return new ExhibitActiveState(); } } 

    private class ExhibitReadyState : ExhibitInitialState {} 
    private class ExhibitInactiveState : ExhibitInitialState {} 
    private class ExhibitCompleteState : ExhibitState {} 
    private class ExhibitActiveState : ExhibitState {} 
} 

public abstract class ExhibitInitialState : ExhibitState {} 

上記のサンプルでは、​​単純なアプローチを示しています。通常は、getメソッドで状態の新しいインスタンスを作成するのではなく、静的インスタンスを持つことで、比較が容易になります。

列挙型に類似して、ExhibitState.Readyまたは他の状態を入力することもできます。

が提案@Fabioアプローチと比較して
public void SetInitial(ExhibitInitialState initState) { ... } 

、あなたが値をミックスできなかった利点を持っていると思います。また、ベースクラスExhibitInitialStateは、最初に設定することができます状態を制限することができます。さらに、特に状態に関連する:非常に一般的であり、その振る舞いも特定の状態のために変わるべきである。このクラスベースのアプローチでは、特定のExhibitState実装でこの動作を実装でき、それによってenumベースのアプローチで存在する可能性のある多くのswitchステートメントが回避されます。

+0

このルートに行く場合、毎回状態サブクラスの新しいインスタンスを作成しないことを検討してください。 C#6の新しい言語機能(読み取り専用の自動プロパティ)を使用して、このクラスから毎回同じインスタンスを取得できます。public static ExhibitInitialState Ready {get;} = new ExhibitReadyState();これにより、等価性とハッシュを混乱させることなく、等価性のチェックによる状態の比較が容易になります。 –

+0

@BradleyUffnerはい、そうです。私はサンプルを短くシンプルにしたいと思っていました。 – Markus

関連する問題