1

ステートレスを使用して、複数のクラスに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);
    }
}

これを実装する方法についての洞察をいただければ幸いです。

編集:私の最終的な目標は、ステートレスを使用して、最大40の異なるFSMを持つIVR( IVR )システムを実装することです。ステートマシンは、コールフローとユーザーがシステムと対話する方法を担当します。私はすでにデモステートマシンを動作させていますが、ステートとトリガーはそのクラスにローカルです。

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

ステートマシンを基本クラスに入れることができれば、1セットのトリガー(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などを処理するメソッドがありますが、それはその限りでは)。

もし私があなただったら、私はあなたの「列挙型」を本当に別々のクラスにして、各状態とイベント/トリガーに独自の表現クラスを持たせ、すべてが共有できる基本クラスをそれらに与えます(つまり、状態には1つ、トリガーには1つです) )。
そして、いくつかのステート マシン パターンを使用して状態を通過し、それらの間を切り替えることもできます。

または、持っているものに応じて、ビジターを使用して (より複雑な階層がある場合など)、物事を処理することもできます (ただし、これはより複雑なケースやさまざまなパターンを組み合わせる場合に必要であり、多くの場合必要です)。
いくつかの詳細、それで何をしたいのか、目標などの全体像を除いて、言うのは難しいです。多くの方法があります。

免責事項:あなたが言及している「ステートレス」に精通していないので、他の方法があるかもしれません。

于 2012-04-03T19:07:46.017 に答える