Локальный экземпляр базового перечисления или передаваемый набор перечислений? - PullRequest
1 голос
/ 03 апреля 2012

Я использую 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 для реализации системы IVR ( IVR ), которая имеет ~ 40 различныхФСМ. Государственные машины сбудет нести ответственность за поток вызовов и за то, как пользователь взаимодействует с системой.У меня уже работает демо-конечный автомат, но состояния и триггеры локальны для этого класса.

Я просто пытаюсь понять, смогу ли я вывести конечный автомат в базовый класс, чтобы мне не приходилось передавать конечный автомат вспомогательным функциям.

Если я могу поместить конечный автомат в базовый класс, я думаю, что я мог бы использовать один набор триггеров (это были бы события от телефонного звонка, такие как 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 ]

2 голосов
/ 03 апреля 2012

Обратите внимание, что тип 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); 
        .... 
1 голос
/ 03 апреля 2012

вы не можете сделать это с перечислениями,
не существует «базового класса» для разных перечислений (есть внутренне, для ValueType-ов и т. Д., Но вы не можете использовать это - Enum. имеет методы для работы с перечислениями GetValues ​​и т. д., но это далеко не так).

На вашем месте я бы сделал ваши перечисления действительно отдельными классами, поэтому у каждого состояния и события / триггера есть свой собственный класс представления - и дал бы им базовый класс, которым все могли бы поделиться (я имею в видуодин для состояний, один для триггеров).
И затем вы могли бы также использовать некоторый шаблон конечного автомата для прохождения состояний и переключения между ними.

Или, в зависимости от того, что у вас может быть, вы можете нанять посетителя (если у вас более сложная иерархия и т. Д.), Чтобы просматривать вещи и т. Д. (Но это для более сложных случаев и объединения различных шаблонов, которыечасто необходимо).
Трудно сказать, если не считать некоторых подробностей, что вы хотите с этим сделать, цели и т. д. общую картину, есть много способов.

заявление об отказе: не знаком с «Безгражданством», на которое вы ссылаетесь, так же как и другие способы для него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...