I am using Stateless to implement FSM's in multiple classes. (http://code.google.com/p/stateless/)

I want to use a base class for firing triggers and logging, etc.. I also want to enforce that any class inheriting my baseFSM class implements a StateMachine with their own local States and Triggers.

However my problem is, enum's cannot be abstracted or passed to functions.

By the way, Stateless says "Generic support for states and triggers of any .NET type (numbers, strings, enums, etc.)" so if there is a better way to go about this let me know.

Ideally this is what I would like to implement (or something that can work the same way).

BaseFSM class:

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

A class that implements 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 I would even take something like this:

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

Any insight on how I can go about implementing this would be greatly appreciated!

Edit: My ultimate goal is using Stateless to implement an IVR (IVR) system that has ~40 different FSM's. The state machines will be responsible for call flow and how the user interacts with the system. I already have a demo state machine working, but the States and Triggers are local to that class.

I am just trying to see if I can pull the state machine out to a base class so I don't have to pass the state machine to helper functions.

If I can put the state machine in a base class, I think I could use one set of Triggers (these would be events from the phone call like CallConnected, UserPressedDigit, CallDisconnected, PromptDonePlaying, etc) and only have to implement States for each FSM.

ANSWER (at least how I am using this) thanks to @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);
有帮助吗?

解决方案

Note that the Enum type represents a reference to a boxed value of an enum; it doesn't refer to the entire enum type. So, for example, this code is valid:

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

You are trying to parameterize the entire enum type; the tool for parameterizing types is generics. With that in mind, your code could be made to work with some modifications:

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

其他提示

you can't do that with enums,
there is no 'base class' for different enums (there is internally, and for ValueType-s etc. but you cannot use that - Enum. has methods to deal with enums GetValues etc. but that's as far as that goes).

If I were you, I'd make your 'enums' be separate classes really, so each state and event/trigger have their own representation class - and give them the base class that all could share (I mean one for states one for triggers).
And then you could also use some state machine pattern to go through states, and flip in between them.

Or depending on what you might have you might want to employ a visitor (if you have a more complex hierarchy etc.) to go through things etc. (but that's for more complex cases and combining different patterns, which often is necessary).
It's hard to say, short of some more details, what you want to do with that, the goal etc. big picture, there are many ways.

disclaimer: not familiar with 'Stateless' you're referring to, so might other ways for it.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top