2012-04-03 8 views
1

Ich verwende Stateless, um FSMs in mehreren Klassen zu implementieren. (http://code.google.com/p/stateless/)Lokale Instanz einer Base Enum oder Passing Enum Collection?

Ich mag eine Basisklasse zum Brennen von Triggern und Protokollierung verwenden, etc .. Ich mag auch erzwingen, dass jede Klasse erbt meine baseFSM Klasse eine Statemachine mit ihren eigenen lokalen Staaten und Trigger implementiert.

Allerdings ist mein Problem, enum kann nicht abstrahiert oder an Funktionen übergeben werden.

Übrigens sagt Staatenlos "Generische Unterstützung für Zustände und Auslöser von jedem .NET-Typ (Zahlen, Strings, enums, etc.)" also, wenn es einen besseren Weg gibt, darüber zu gehen, lass es mich wissen.

Idealerweise möchte ich das implementieren (oder etwas, das auf die gleiche Weise funktionieren kann).

BaseFSM Klasse:

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

Eine Klasse, die BaseFSM implementiert:

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 ich so etwas wie dies würde auch nehmen:

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

ich gehen kann Einsicht darüber, wie über die Umsetzung dieses würde sehr geschätzt werden!

Bearbeiten: Mein ultimatives Ziel ist die Verwendung von Staatenlos, ein IVR (IVR) System zu implementieren, das ~ 40 verschiedene FSM hat. Die Zustandsautomaten sind verantwortlich für den Anrufverlauf und wie der Benutzer mit dem System interagiert. Ich habe bereits eine Demo-Zustandsmaschine, aber die States und Trigger sind lokal in dieser Klasse.

Ich versuche nur zu sehen, ob ich die Zustandsmaschine zu einer Basisklasse herausziehen kann, so dass ich die Zustandsmaschine nicht an Hilfsfunktionen übergeben muss.

Wenn ich die State Machine in eine Basisklasse legen kann, denke ich, ich könnte einen Satz von Triggern verwenden (dies wären Ereignisse aus dem Telefonanruf wie CallConnected, UserPressedDigit, CallDisconnected, PromptDonePlaying, etc) und müssen nur implementieren Staaten für jede FSM.

ANTWORT (zumindest, wie ich das bin mit) dank @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); 

Antwort

2

Beachten Sie, dass der Typ Enum einen Verweis auf einen Box-Wert einer Enumeration darstellt; Es bezieht sich nicht auf den gesamten Enum-Typ. So zum Beispiel, dieser Code ist gültig:

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

Sie versuchen den gesamten Aufzählungstyp zu parametrieren; Das Werkzeug zum Parametrieren von Typen ist Generika. In diesem Sinne könnte Ihr Code mit einigen Modifikationen arbeiten:

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

Jetzt das, wenn sehr fantastisch! Vielen Dank! – jpiccolo

+0

das ist eine gute antwort für was er braucht! Aber Enum gibt Generika keine starke Typisierung oder Beschränkung - Sie könnten genauso gut Objekte verwenden und würden sich nicht sehr unterscheiden. Übrigens. Sie sollten die generics beschränken auf: struct mindestens (das ist, was möglich ist). – NSGaga

+0

@NSGaga Sie sind natürlich richtig. Ich fügte keine Einschränkungen hinzu, weil sie nicht notwendig erschienen. Es gibt nichts in der Basisklasse, das brechen würde, wenn Sie einen Typ verwenden, der * nicht enum ist. Jon Skeet hat ein Projekt namens "unbeschränkte Melodie", mit dem Sie Enum-Constraints anwenden können, indem Sie IL umschreiben - die CLR unterstützt Enum-Constraints, nur C# nicht. – phoog

1

Sie können das nicht mit Aufzählungen,
es keine ‚Basisklasse‘ ist für verschiedene Aufzählungen (Es gibt intern, und für ValueType-s usw. aber Sie können das nicht verwenden - Enum. hat Methoden, um mit Enums GetValues ​​usw. umzugehen, aber das ist soweit das geht.

Wenn ich Sie wäre, würde ich Ihre 'enums' wirklich getrennte Klassen machen, also haben jeder Zustand und Ereignis/Auslöser eine eigene Repräsentationsklasse - und geben Sie die Basisklasse, die alle teilen können (ich meine eine für gibt einen für Trigger an.
Und dann könnten Sie auch ein Zustandsautomatenmuster verwenden, um Zustände zu durchlaufen und zwischen ihnen zu wechseln.

Oder je nachdem, was Sie haben könnten, könnten Sie einen Besucher beschäftigen (wenn Sie eine komplexere Hierarchie usw. haben), um Dinge zu durchlaufen usw.(Aber das ist für komplexere Fälle und die Kombination verschiedener Muster, die oft notwendig ist).
Es ist schwer zu sagen, kurz, einige weitere Details, was Sie damit tun wollen, das Ziel usw. großes Bild, gibt es viele Möglichkeiten.

Haftungsausschluss: Nicht vertraut mit "Stateless" Sie beziehen sich auf, so könnte andere Möglichkeiten dafür.

+0

Ich habe meinen Beitrag mit meinem ultimativen Ziel aktualisiert. – jpiccolo