2012-04-03 201 views
1

我正在使用無狀態來實現多個類中的FSM。 (http://code.google.com/p/stateless/基本枚舉的本地實例或傳遞枚舉集合?

我想用一個基類激活觸發器和記錄等。 我也想強制執行,任何類繼承我的baseFSM類實現自己的本地國和觸發狀態機。

但是我的問題是,枚舉的不能被抽象或傳遞給函數。順便說一下,Stateless說:「對任何.NET類型(數字,字符串,枚舉等)的狀態和觸發器的通用支持」,所以如果有更好的方式去解決這個問題,請讓我知道。

理想情況下,這是我想要實現的(或者可以以相同方式工作的東西)。

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

實現BaseFSM類:

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)系統。狀態機將負責呼叫流程以及用戶與系統的交互方式。我已經有一個演示狀態機工作,但狀態和觸發器是本地的。

我只是想看看我是否可以將狀態機拉出到基類,所以我不必將狀態機傳遞給輔助函數。如果我可以把狀態機放在一個基類中,我想我可以使用一組觸發器(這些是來自CallConnected,UserPressedDigit,CallDisconnected,PromptDonePlaying等電話的事件),並且只需要實現每個FSM的狀態。

的答案(至少我是如何使用這個)由於@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 2012-04-03 20:14:49

+0

這是他需要的一個很好的答案!但Enum並沒有給泛型提供任何強大的輸入和約束 - 你也可以使用對象並且不會有太大的區別。順便說一句。你應該將泛型限制在:struct至少(這是可能的)。 – NSGaga 2012-04-03 23:05:59

+0

@NSGaga當然你是對的。我沒有添加任何約束,因爲他們似乎不必要;如果你使用了*不是*枚舉的類型,那麼基類中就沒有任何東西會被破壞。 Jon Skeet有一個名爲「無限制旋律」的項目,允許你通過重寫IL來應用枚舉約束--CLR支持枚舉約束,只有C#不支持。 – phoog 2012-04-04 14:39:02

1

你不能做到這一點與枚舉,
有不同的枚舉沒有「基地班」(有內部的,對於ValueType-s等,但你不能使用它 - Enum。有處理枚舉GetValues等的方法,但是就這一點而言)。

如果我是你,我會讓你的'枚舉'成爲單獨的類,所以每個狀態和事件/觸發器都有它們自己的表示類 - 並給它們所有可以共享的基類(我的意思是說一個觸發器)。
然後你也可以使用一些狀態機模式來遍歷狀態,並在它們之間翻轉。

或者取決於你可能想要僱用的訪問者(如果你有更復雜的層次結構等)通過事情等。(但那是更復雜的情況,並結合不同的模式,這往往是必要的)。
很難說,缺少一些更多的細節,你想做什麼,目標等大圖,有很多方法。

免責聲明:不熟悉你指的「無狀態」,所以可能有其他方式。

+0

我更新了我的帖子,我的最終目標。 – jpiccolo 2012-04-03 19:42:17