1

我正在使用 Stateless 在多个类中实现 FSM。(http://code.google.com/p/stateless/

我想使用一个基类来触发触发器和日志记录等。我还想强制任何继承我的 baseFSM 类的类都使用它们自己的本地状态和触发器来实现 StateMachine。

但是我的问题是,枚举不能被抽象或传递给函数。

顺便说一句,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);
        ....

或者我什至会采取这样的做法:

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

任何关于我如何实现这一点的见解将不胜感激!

编辑:我的最终目标是使用 Stateless 来实现具有约 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);
4

2 回答 2

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); 
        .... 
于 2012-04-03T19:43:58.230 回答
1

你不能用枚举来做到这一点,
不同的枚举没有“基类”(内部有,对于 ValueType-s 等,但你不能使用它 - Enum. 有处理枚举 GetValues 等的方法,但那是就目前而言)。

如果我是你,我会让你的“枚举”真正成为单独的类,所以每个状态和事件/触发器都有自己的表示类 - 并给它们一个所有人都可以共享的基类(我的意思是一个用于状态一个用于触发器)。
然后你也可以使用一些状态机模式来遍历状态,并在它们之间翻转。

或者根据您可能拥有的内容,您可能想要雇用访问者(如果您有更复杂的层次结构等)来处理事情等(但这是针对更复杂的情况并结合不同的模式,这通常是必要的)。
很难说,缺少更多细节,你想用它做什么,目标等等。大局,有很多方法。

免责声明:不熟悉您所指的“无状态”,因此可能有其他方式。

于 2012-04-03T19:07:46.017 回答