2012-04-03 7 views
1

私はFSMを複数のクラスに実装するためにステートレスを使用しています。 (http://code.google.com/p/stateless/ベースenumまたはenumコレクションを渡すローカルインスタンス?

私は は、私はまた、任意のクラスを継承私baseFSMクラスは独自のローカル米国およびトリガとステートマシンを実装することを強制したい...トリガーやログなどを発射するための基本クラスを使用します。

しかし私の問題は、列挙型を抽象化したり関数に渡すことができないことです。

ところで、ステートレスは「どの.NETタイプ(数値、文字列、列挙型など)の状態とトリガも一般的にサポートしています」と言っています。

理想的には、これは私が実装したいもの(または同じように動作するもの)です。

BaseFSMクラス:BaseFSMを実装

public abstract class BaseFSM : IStateMachine 
{ 
    #region Implementation of IStateMachine 

    public ICall LocalCall { get; set; } 

    #endregion 

    internal abstract enum State {} 
    internal abstract enum Trigger {} 

    internal abstract StateMachine<State, Trigger> fsm { get; set; } 

    public abstract void Fire(Enum trigger); 
} 

クラス:

class Incoming_Initial : BaseFSM 
{ 
    private enum State 
    { 
     WaitForCallToBeAnswered, 
     CallConnected, 
     CallNeverConnected, 
     CheckForCustomIntro, 
     PlayIntro, 
     PlayPleaseEnterPin, 
     ReadLanguageSettings, 
     ChooseLanguage, 
     ValidatePIN, 
     PINWasInvalid, 
     IdentifyUser 
    } 

    private enum Trigger 
    { 
     Yes, 
     No, 
     DigitPressed, 
     PromptDonePlaying, 
     PromptTimerElapse, 
     Done 
    } 

    public Incoming_Initial(ICall call) 
    { 
     LocalCall = call; 
     fsm = new StateMachine<this.State, this.Trigger>(State.WaitForCallToBeAnswered); 
     .... 

OR私もこのような何かを取る:

public class myStateMachine 
{ 
    private enum State{} 
    private enum Trigger{} 
    private StateMachine<State, Trigger> stateMachine; 

    public myStateMachine (Enum _states, Enum _triggers, Enum _startState) 
    { 
     State = _states; 
     Trigger = _triggers; 

     stateMachine = new StateMachine<State, Trigger>(_startState); 
    } 
} 

私は行くことができる方法上の任意の洞察力これを実装することについて大いに感謝します!

編集:究極の目標は、ステートレスを使用して〜40の異なるFSMを持つIVR(IVR)システムを実装することです。ステートマシンは、コールフローとユーザーがシステムとやりとりする方法を担当します。デモ状態マシンはすでに動作していますが、ステートとトリガーはそのクラスのローカルです。

ステートマシンを基本クラスにプルできるかどうかを確認しようとしているので、ステートマシンをヘルパ関数に渡す必要はありません。

状態マシンを基本クラスに置くことができるのであれば、私はTriggers(CallConnected、UserPressedDigit、CallDisconnected、PromptDonePlayingなどのような電話からのイベント)を使用でき、各FSMの状態。

ANSWER(私はこれを使用しています少なくともどのように)@phoogのおかげ:

 public abstract class BaseFSM <TState> : IStateMachine 
    { 
     #region Implementation of IStateMachine 

     public ICall LocalCall { get; set; } 

     #endregion 

     public enum Triggers 
     { 
      Yes = 0, 
      No, 
      DigitPressed, 
      PromptDonePlaying, 
      PromptTimerElapse, 
      Done 
     } 

     protected IList<TState> States { get; set; } 
     protected StateMachine<TState, Triggers> fsm { get; set; } 
     ... 

    class Incoming_Initial : BaseFSM<Incoming_Initial.State> 
    { 
     internal enum State 
     { 
      WaitForCallToBeAnswered, 
      CallConnected, 
      CallNeverConnected, 
      CheckForCustomIntro, 
      PlayIntro, 
      PlayPleaseEnterPin, 
      ReadLanguageSettings, 
      ChooseLanguage, 
      ValidatePIN, 
      PINWasInvalid, 
      IdentifyUser 
     } 

     public Incoming_Initial(ICall call) 
     { 
      LocalCall = call; 
      LocalCall.CallEventHandler += new CallEventHandler(LocalCall_CallEventHandler); 

      States = (State[]) Enum.GetValues(typeof (State)); 

      fsm = new StateMachine<State, Triggers>(State.WaitForCallToBeAnswered); 

答えて

2

Enumタイプは、列挙型のボックス化された値への参照を表します。列挙型全体を参照するものではありません。たとえば、このコードは有効です。

enum Something { Value0, Value1, Value2, Value3 } 
void ProcessAnEnumValue(Enum value) 
{ 
    //...whatever 
} 
void CallTheMethod() 
{ 
    ProcessAnEnumValue(Something.Value2); 
} 

列挙型全体をパラメータ化しようとしています。タイプをパラメータ化するためのツールはジェネリックです。これを念頭に置いて、あなたのコードはいくつかの変更を加えて動作させることができます:

public abstract class BaseFSM<TState, TTrigger> : IStateMachine 
{ 
    #region Implementation of IStateMachine 
    public ICall LocalCall { get; set; } 
    #endregion 

    protected IList<TState> States { get; set; } 
    protected IList<TTrigger> Triggers { get; set; } 

    protected StateMachine<TState, TTrigger> fsm { get; set; } 

    public abstract void Fire(TTrigger trigger); 
} 

class Incoming_Initial : BaseFSM<Incoming_Initial.State, Incoming_Initial.Trigger> 
{ 
    public enum State 
    { 
     WaitForCallToBeAnswered, 
     CallConnected, 
     CallNeverConnected, 
     CheckForCustomIntro, 
     PlayIntro, 
     PlayPleaseEnterPin, 
     ReadLanguageSettings, 
     ChooseLanguage, 
     ValidatePIN, 
     PINWasInvalid, 
     IdentifyUser 
    } 

    public enum Trigger 
    { 
     Yes, 
     No, 
     DigitPressed, 
     PromptDonePlaying, 
     PromptTimerElapse, 
     Done 
    } 

    public Incoming_Initial(ICall call) 
    { 
     States = (State[])Enum.GetValues(typeof(State)); 
     Triggers = (Trigger[])Enum.GetValues(typeof(Trigger)); 

     LocalCall = call; 
     fsm = new StateMachine<State, Trigger>(State.WaitForCallToBeAnswered); 
     .... 
+0

これは非常に素晴らしい!どうもありがとうございました! – jpiccolo

+0

これは彼が必要としていることに対する良い答えです!しかし、Enumはジェネリックに厳密な型や制約を与えていません。オブジェクトを使うこともできますし、大きな違いを感じることもありません。 Btw。ジェネリックスを以下のように制約する必要があります:struct少なくとも(それは可能です)。 – NSGaga

+0

@NSGagaもちろん、あなたは正しいです。彼らは必要ないように私は制約を加えなかった。列挙型ではない型を使用した場合、基本クラスには何もありません。 Jon Skeetには "unconstrained melody"というプロジェクトがあり、ILを書き換えることで列挙制約を適用できます.CLRは列挙制約をサポートしていますが、C#だけはそうではありません。 – phoog

1

あなたは列挙型、
と異なる列挙型には「基底クラスが」(存在しないことはできません内部的にはValueType-sなどがありますが、使用することはできません - Enum。GetValuesなどのenumを処理するメソッドがありますが、それはそれまでのところです)。

私があなただったら、私はあなたの 'enums'を本当に別のクラスにしたいので、それぞれの状態とイベント/トリガーは独自の表現クラスを持っています。トリガーの1つを述べる)。
また、ステートマシンのパターンを使用してステートを通過させ、それらのステートを反転させることもできます。

あなたが持っている可能性のあるものによっては、訪問者(階層がもっと複​​雑な場合など)を使用して、物などを通過することもできます。(しかし、これはもっと複雑なケースや、しばしば必要な異なるパターンを組み合わせるためのものです)。
もう少し詳しく説明していませんが、これでやりたいこと、目標などの大きな画像は、いろいろあります。

免責事項:あなたが言及している 'ステートレス'には慣れていないので、他の方法もあります。

+0

私の究極の目標を掲示して更新しました。 – jpiccolo

関連する問題