share
Stack OverflowSimple state machine example in C#?
[+316] [22] Jennifer Owens
[2011-05-07 20:22:39]
[ c# state-machine ]
[ https://stackoverflow.com/questions/5923767/simple-state-machine-example-in-c ]

Update:

Again thanks for the examples, they have been very helpful and with the following, I don't mean to take anything away from them.

Aren't the currently given examples, as far as I understand them & state-machines, only half of what we usually understand by a state-machine?
In the sense that the examples do change state but that's only represented by changing the value of a variable (and allowing different value- changes in different states), while usually, a state machine should also change its behavior, and behavior not (only) in the sense of allowing different value changes for a variable depending on the state, but in the sense of allowing different methods to be executed for different states.

Or do I have a misconception of state machines and their common use?


Original question:

I found this discussion about state machines & iterator blocks in c# [1] and tools to create state machines and whatnot for C#, so I found a lot of abstract stuff but as a noob, all of this is a little confusing.

So it would be great if someone could provide a C# source code-example that realizes a simple state machine with perhaps 3,4 states, just to get the gist of it.

Are you wondering about state machines in general or just iterator based ones? - Skurmedel
(3) There is .Net Core Stateless lib with examples, DAGs daigram etc. - worth reviewing: hanselman.com/blog/… - zmische
[+483] [2011-05-07 21:16:59] Juliet

Let's start with this simple state diagram:

simple state machine diagram

We have:

  • 4 states (Inactive, Active, Paused, and Exited)
  • 5 types of state transitions (Begin Command, End Command, Pause Command, Resume Command, Exit Command).

You can convert this to C# in a handful of ways, such as performing a switch statement on the current state and command, or looking up transitions in a transition table. For this simple state machine, I prefer a transition table, which is very easy to represent using a Dictionary:

using System;
using System.Collections.Generic;

namespace Juliet
{
    public enum ProcessState
    {
        Inactive,
        Active,
        Paused,
        Terminated
    }

    public enum Command
    {
        Begin,
        End,
        Pause,
        Resume,
        Exit
    }

    public class Process
    {
        class StateTransition
        {
            readonly ProcessState CurrentState;
            readonly Command Command;

            public StateTransition(ProcessState currentState, Command command)
            {
                CurrentState = currentState;
                Command = command;
            }

            public override int GetHashCode()
            {
                return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode();
            }

            public override bool Equals(object obj)
            {
                StateTransition other = obj as StateTransition;
                return other != null && this.CurrentState == other.CurrentState && this.Command == other.Command;
            }
        }

        Dictionary<StateTransition, ProcessState> transitions;
        public ProcessState CurrentState { get; private set; }

        public Process()
        {
            CurrentState = ProcessState.Inactive;
            transitions = new Dictionary<StateTransition, ProcessState>
            {
                { new StateTransition(ProcessState.Inactive, Command.Exit), ProcessState.Terminated },
                { new StateTransition(ProcessState.Inactive, Command.Begin), ProcessState.Active },
                { new StateTransition(ProcessState.Active, Command.End), ProcessState.Inactive },
                { new StateTransition(ProcessState.Active, Command.Pause), ProcessState.Paused },
                { new StateTransition(ProcessState.Paused, Command.End), ProcessState.Inactive },
                { new StateTransition(ProcessState.Paused, Command.Resume), ProcessState.Active }
            };
        }

        public ProcessState GetNext(Command command)
        {
            StateTransition transition = new StateTransition(CurrentState, command);
            ProcessState nextState;
            if (!transitions.TryGetValue(transition, out nextState))
                throw new Exception("Invalid transition: " + CurrentState + " -> " + command);
            return nextState;
        }

        public ProcessState MoveNext(Command command)
        {
            CurrentState = GetNext(command);
            return CurrentState;
        }
    }


    public class Program
    {
        static void Main(string[] args)
        {
            Process p = new Process();
            Console.WriteLine("Current State = " + p.CurrentState);
            Console.WriteLine("Command.Begin: Current State = " + p.MoveNext(Command.Begin));
            Console.WriteLine("Command.Pause: Current State = " + p.MoveNext(Command.Pause));
            Console.WriteLine("Command.End: Current State = " + p.MoveNext(Command.End));
            Console.WriteLine("Command.Exit: Current State = " + p.MoveNext(Command.Exit));
            Console.ReadLine();
        }
    }
}

As a matter of personal preference, I like to design my state machines with a GetNext function to return the next state deterministically [1], and a MoveNext function to mutate the state machine.

[1] http://en.wikipedia.org/wiki/Pure_function

(71) +1 for the correct implementation of GetHashCode() using primes. - John Alexiou
(17) Could you please explain me the purpose of GetHashCode()? - Siddharth
(16) @Siddharth: The StateTransition class is used as key in the dictionary and equality of keys are important. Two distinct instances of StateTransition should be considered equal as long as they represent the same transition (e.g. CurrentState and Command are the same). To implement equality you have to override Equals as well as GetHashCode. In particular the dictionary will use the hash code and two equal objects must return the same hash code. You also get good performance if not too many non-equal objects share the same hash code which is why GetHashCode is implemented as shown. - Martin Liversage
I was asked to identify this in an interview and I didn't label it as a state machine. But I've 99.9% coded in vb so reading un highlighted code in c# in an interview was a bit challenging. I like your version using a dictionary, it's a bias I have too, refactoring switches to dictionaries. +1 for diagram and clear code! - Richard Griffiths
The diagram image is missing, can you attach a new one? 10x - Yair Nevet
(17) While this surely gets you a state machine (and a proper C#'ish implementation as well), I feel it is still missing the answer to the OP's question about changing behaviour? After all, it just calculates states but the behaviour related to state changes, the actual meat of the program and usually called Entry/Exit events, is still missing. - stijn
(2) If someone it's gonna need it: I adjusted this tate machine and used it in my unity game. It's available on git hub: github.com/MarcoMig/Finite-State-Machine-FSM - Max_Power89
(2) Thank you for the clean code however, I have a quick question. If there was a specific action to be done when entering a state how would I implement it using this example? Thank you very much. - DoubleDunk
@Siddharth You can also use a Tuple for this. - Asad Saeeduddin
Is this hashCode implementation really correct? What if there is an overflow? I know that will crash when using Swift, so you should XOR. - Mazyod
(2) @Mazyod: If there is an overflow, it will wrap around. This hashcode implementation is pretty standard, though I don't love that the OP used 31 twice; that will likely cause more collisions than necessary.. - Brian
@Brian Thanks for the clarification, but I can't get over my traumatic experience when it crashed my Swift application. I'd need to research more about the drawbacks and advantages of + vs ^ - Mazyod
(2) @Brian it kinda bothers me to see code with magic numbers (numbers with unexplained meaning), I mean why this exact number was picked? I dunno, it just felt right... - rluks
(2) @Max_Power89 your "adjustments" aren't much? Can you really claim to be the proprietor of the design by publishing it on Git? - Thomas
Another advantage of this design is that the various states and their transitions are not spread out -- the definition of the states are found in one place. - Thomas
(1) Love the dictionary implementation but the complexities of needing to implement Equals() and GetHashCode() are a real distraction from the question subject of state machines. - FBryant87
(3) @FBryant87, If you use modern C# you can do the following: GetHashCode() => (Command, State).GetHashCode() Something like that. Much simpler now days! - Jon49
1
[+89] [2011-05-10 00:24:14] Remo Gloor

You might want to use one of the existing open source Finite State Machines. E.g. bbv.Common.StateMachine found at http://code.google.com/p/bbvcommon/wiki/StateMachine. It has a very intuitive fluent syntax and a lot of features such as, enter/exit actions, transition actions, guards, hierarchical, passive implementation (executed on the thread of the caller) and active implementation (own thread on which the fsm runs, events are added to a queue).

Taking Juliets example the definition for the state machine gets very easy:

var fsm = new PassiveStateMachine<ProcessState, Command>();
fsm.In(ProcessState.Inactive)
   .On(Command.Exit).Goto(ProcessState.Terminated).Execute(SomeTransitionAction)
   .On(Command.Begin).Goto(ProcessState.Active);
fsm.In(ProcessState.Active)
   .ExecuteOnEntry(SomeEntryAction)
   .ExecuteOnExit(SomeExitAction)
   .On(Command.End).Goto(ProcessState.Inactive)
   .On(Command.Pause).Goto(ProcessState.Paused);
fsm.In(ProcessState.Paused)
   .On(Command.End).Goto(ProcessState.Inactive).OnlyIf(SomeGuard)
   .On(Command.Resume).Goto(ProcessState.Active);
fsm.Initialize(ProcessState.Inactive);
fsm.Start();

fsm.Fire(Command.Begin);

Update: The project location has moved to: https://github.com/appccelerate/statemachine


(5) Thank you for referencing this excellent open source state machine. Can I ask how can I get current state ? - ramazan polat
(4) You can't and you shouldn't. State is something unstable. When you request the state it is possible that you are in the middle of a transition. All actions should be done within transitions, state entry and state exits. If you really want to have the state then you can add a local field and assign the state in a entry action. - Remo Gloor
(4) The question is for what do you "need" it and if you really need the SM state or some other kind of state. E.g. if you need some display text then several stated could have the same display text for example if preparing for send has multiple sub states. In this case you should do exactly what you intend to do. Update some display text at the correct places. E.g. within ExecuteOnEntry. If you need more info then ask a new Question and state exactly your problem as this is getting off topic here. - Remo Gloor
Ok I am asking a new question and waiting you to reply. Because I don't think somebody else solve this problem since you have the best answer but still questioner didn't accept. I will post question url here. Thanks. - ramazan polat
This is the question I have asked: link - ramazan polat
(5) +1 for the fluent and declarative API. It's awesome. BTW, the google code seems to be outdated. Their newest project site is on GitHub here - KFL
@ Ramazan POLAT : yes you can do it (of course). you have to subscribe to the event TransitionCompleted then in your callback read the e.NewStateId field. Be aware that the event is triggered right before entering the new state, this is not a StateChanged event. - Giova
Note that the library mention is no longer maintained. They have renamed it Appccelerate.StateMachine and are maintaining that one. - fredrik
2
[+68] [2011-05-07 22:03:01] Pete Stensønes

Here's an example of a very classic finite state machine, modelling a very simplified electronic device (like a TV)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace fsm
{
class Program
{
    static void Main(string[] args)
    {
        var fsm = new FiniteStateMachine();
        Console.WriteLine(fsm.State);
        fsm.ProcessEvent(FiniteStateMachine.Events.PlugIn);
        Console.WriteLine(fsm.State);
        fsm.ProcessEvent(FiniteStateMachine.Events.TurnOn);
        Console.WriteLine(fsm.State);
        fsm.ProcessEvent(FiniteStateMachine.Events.TurnOff);
        Console.WriteLine(fsm.State);
        fsm.ProcessEvent(FiniteStateMachine.Events.TurnOn);
        Console.WriteLine(fsm.State);
        fsm.ProcessEvent(FiniteStateMachine.Events.RemovePower);
        Console.WriteLine(fsm.State);
        Console.ReadKey();
    }

    class FiniteStateMachine
    {
        public enum States { Start, Standby, On };
        public States State { get; set; }

        public enum Events { PlugIn, TurnOn, TurnOff, RemovePower };

        private Action[,] fsm;

        public FiniteStateMachine()
        {
            this.fsm = new Action[3, 4] { 
                //PlugIn,       TurnOn,                 TurnOff,            RemovePower
                {this.PowerOn,  null,                   null,               null},              //start
                {null,          this.StandbyWhenOff,    null,               this.PowerOff},     //standby
                {null,          null,                   this.StandbyWhenOn, this.PowerOff} };   //on
        }
        public void ProcessEvent(Events theEvent)
        {
            this.fsm[(int)this.State, (int)theEvent].Invoke();
        }

        private void PowerOn() { this.State = States.Standby; }
        private void PowerOff() { this.State = States.Start; }
        private void StandbyWhenOn() { this.State = States.Standby; }
        private void StandbyWhenOff() { this.State = States.On; }
    }
}
}

(8) for anyone new to state machines, this is an excellent first example to get ones feet wet first. - PositiveGuy
(2) I am new to state machines and seriously, this has brought me The Light - thanks! - MC5
(2) I liked this implementation. For anyone who might stumble on this, a slight "improvement". In the FSM class, I added private void DoNothing() {return;} and replaced all instances of null with this.DoNothing. Has the pleasant side effect of returning the current state. - Sethmo011
(2) I'm wondering if there's a reasoning behind some of these names. When I look at this, my first intuition is to rename the elements of the States to Unpowered, Standby, On. My reasoning is that if someone asked me what state my television is in, I would say "Off" and not "Start". I also changed StandbyWhenOn and StandbyWhenOff to TurnOn and TurnOff. That makes the code read more intuitively, but I wonder if there are conventions or other factors that make my terminology less appropriate. - Jason Hamje
Seems reasonable, I was not really following any state naming convention; name as makes sense for whatever you model. - Pete Stensønes
Incredibly intuitive and easy to understand. But do you mind turning it off? - Marcelo Scofano Diniz
3
[+21] [2012-10-15 09:12:16] skrebbel

Some shameless self-promo here, but a while ago I created a library called YieldMachine [1] which allows a limited-complexity state machine to be described in a very clean and simple way. For example, consider a lamp:

state machine of a lamp

Notice that this state machine has 2 triggers and 3 states. In YieldMachine code, we write a single method for all state-related behavior, in which we commit the horrible atrocity of using goto for each state. A trigger becomes a property or field of type Action, decorated with an attribute called Trigger. I've commented the code of the first state and its transitions below; the next states follow the same pattern.

public class Lamp : StateMachine
{
    // Triggers (or events, or actions, whatever) that our
    // state machine understands.
    [Trigger]
    public readonly Action PressSwitch;

    [Trigger]
    public readonly Action GotError;

    // Actual state machine logic
    protected override IEnumerable WalkStates()
    {
    off:                                       
        Console.WriteLine("off.");
        yield return null;

        if (Trigger == PressSwitch) goto on;
        InvalidTrigger();

    on:
        Console.WriteLine("*shiiine!*");
        yield return null;

        if (Trigger == GotError) goto error;
        if (Trigger == PressSwitch) goto off;
        InvalidTrigger();

    error:
        Console.WriteLine("-err-");
        yield return null;

        if (Trigger == PressSwitch) goto off;
        InvalidTrigger();
    }
}

Short and nice, eh!

This state machine is controlled simply by sending triggers to it:

var sm = new Lamp();
sm.PressSwitch(); //go on
sm.PressSwitch(); //go off

sm.PressSwitch(); //go on
sm.GotError();    //get error
sm.PressSwitch(); //go off

Just to clarify, I've added some comments to the first state to help you understand how to use this.

    protected override IEnumerable WalkStates()
    {
    off:                                       // Each goto label is a state

        Console.WriteLine("off.");             // State entry actions

        yield return null;                     // This means "Wait until a 
                                               // trigger is called"

                                               // Ah, we got triggered! 
                                               //   perform state exit actions 
                                               //   (none, in this case)

        if (Trigger == PressSwitch) goto on;   // Transitions go here: 
                                               // depending on the trigger 
                                               // that was called, go to
                                               // the right state

        InvalidTrigger();                      // Throw exception on 
                                               // invalid trigger

        ...

This works because the C# compiler actually created a state machine internally for each method that uses yield return. This construct is usually used to lazily create sequences of data, but in this case we're not actually interested in the returned sequence (which is all nulls anyway), but in the state behaviour that gets created under the hood.

The StateMachine base class does some reflection on construction to assign code to each [Trigger] action, which sets the Trigger member and moves the state machine forward.

But you don't really need to understand the internals to be able to use it.

[1] https://github.com/eteeselink/YieldMachine

(4) The "goto" is only atrocious if it jumps between methods. That, fortunately, is not allowed in C#. - Brannon
Good point! In fact, I would be very impressed if any statically typed language would manage to allow a goto between methods. - skrebbel
(3) @Brannon: which language allows goto to jump between methods? I don't see how that would possibly work. No, goto is problematic because it results in procedural programming (this by itself complicates nice things like unit testing), promotes code repetition (noticed how InvalidTrigger needs to be inserted for every state?) and finally makes the program flow harder to follow. Compare this to (most) other solutions in this thread and you will see that this is the only one where the entire FSM happens in a single method. That's usually enough to raise a concern. - vgru
(2) @Groo, GW-BASIC, for instance. It helps that it doesn't have methods, or even functions. Besides that, I have a very hard time understanding why you find the "program flow harder to follow" in this example. It's a state machine, "going to" a state from another one is the only thing you do. This maps to goto pretty well. - skrebbel
(3) GW-BASIC allows goto to jump between functions, but it doesn't support functions? :) You're right, the "harder to follow" remark is more a general goto issue , indeed not that much of a problem in this case. - vgru
It's old, but just to save the honour of one of the first programming languages I programmed with some decades ago: Of course GW-BASIC supports functions (with DEF FN and more generally with GOSUB/RETURN- because the concept of local variables does not exist, there is no need to dedicate a special variable for function return :-) - Philm
Quite funny but aside from-off topic interesting: Not only state machines were very easy to implement with free goto. It's INKEY$ command still outperforms Java's capabilities for free console input. There are not much programming languages which go head on head with it's easy string manipulation methods. Not only C, but also C++ failed for decades. E.g. the .NET library is very strong at that matter, but a simple RIGHT$ function is missing too (Linq's .Reverse() does not count as simple enough)- (while not too difficult to implement). - Philm
Not mentioning the famous "ON ERROR GOTO 0" was already there. Which is not only a good pattern for life, but ON ERROR GOTO has still advantages e.g. in RAD scenarios over try/catch, which is a bad syntax pattern at least for readability (should be superseded by AOP measures in modern languages itself). Something missing? Yeah: possible calls to assembly, sound, a pen for drawing like in LOGO, and the famous PEEK/POKE (pointers) and TRON commands.. Funny to remember the times of 1986. (MS basic in Apple II: 1979). If interested, you could peek here : antonis.de/qbebooks/gwbasman. - Philm
4
[+16] [2011-05-07 20:37:02] Kevin Hsu

You can code an iterator block that lets you execute a code block in an orchestrated fashion. How the code block is broken up really doesn't have to correspond to anything, it's just how you want to code it. For example:

IEnumerable<int> CountToTen()
{
    System.Console.WriteLine("1");
    yield return 0;
    System.Console.WriteLine("2");
    System.Console.WriteLine("3");
    System.Console.WriteLine("4");
    yield return 0;
    System.Console.WriteLine("5");
    System.Console.WriteLine("6");
    System.Console.WriteLine("7");
    yield return 0;
    System.Console.WriteLine("8");
    yield return 0;
    System.Console.WriteLine("9");
    System.Console.WriteLine("10");
}

In this case, when you call CountToTen, nothing actually executes, yet. What you get is effectively a state machine generator, for which you can create a new instance of the state machine. You do this by calling GetEnumerator(). The resulting IEnumerator is effectively a state machine that you can drive by calling MoveNext(...).

Thus, in this example, the first time you call MoveNext(...) you will see "1" written to the console, and the next time you call MoveNext(...) you will see 2, 3, 4, and then 5, 6, 7 and then 8, and then 9, 10. As you can see, it's a useful mechanism for orchestrating how things should occur.


(9) Obligatory link to fair warning - sehe
Incredible and bold example... But it anchors @sehe comment, so... - Marcelo Scofano Diniz
5
[+11] [2011-05-07 21:20:23] Skurmedel

It's useful to remember that state machines are an abstraction, and you don't need particular tools to create one, however tools can be useful.

You can for example realise a state machine with functions:

void Hunt(IList<Gull> gulls)
{
    if (gulls.Empty())
       return;

    var target = gulls.First();
    TargetAcquired(target, gulls);
}

void TargetAcquired(Gull target, IList<Gull> gulls)
{
    var balloon = new WaterBalloon(weightKg: 20);

    this.Cannon.Fire(balloon);

    if (balloon.Hit)
    {
       TargetHit(target, gulls);
    }
    else
       TargetMissed(target, gulls);
}

void TargetHit(Gull target, IList<Gull> gulls)
{
    Console.WriteLine("Suck on it {0}!", target.Name);
    Hunt(gulls);
}

void TargetMissed(Gull target, IList<Gull> gulls)
{
    Console.WriteLine("I'll get ya!");
    TargetAcquired(target, gulls);
}

This machine would hunt for gulls and try to hit them with water balloons. If it misses it will try firing one until it hits (could do with some realistic expectations ;)), otherwise it will gloat in the console. It continues to hunt until it's out of gulls to harass.

Each function corresponds to each state; the start and end (or accept) states are not shown. There are probably more states in there than modelled by the functions though. For example after firing the balloon the machine is really in another state than it was before it, but I decided this distinction was impractical to make.

A common way is to use classes to represent states, and then connect them in different ways.


This is the second easiest way to implement an FSM besides a loop and switch statement IMO. However, I do prefer using classes to define my states instead of methods. Using 1 class like you're doing usually caused it to get too large. - goku_da_master
6
[+8] [2011-05-10 20:52:09] Pete Stensønes

I'm posting another answer here as this is state machines from a different perspective; very visual.

My original answer is classic imperative code. I think its quite visual as code goes because of the array which makes visualizing the state machine simple. The downside is you have to write all this. Remos [1]'s answer alleviates the effort of writing the boiler-plate code but is far less visual. There is the third alternative; really drawing the state machine.

If you are using .NET and can target version 4 of the run time then you have the option of using workflow's state machine activities. These in essence let you draw the state machine (much as in Juliet [2]'s diagram) and have the WF run-time execute it for you.

See the MSDN article Building State Machines with Windows Workflow Foundation [3] for more details, and this CodePlex site [4] for the latest version.

That's the option I would always prefer when targeting .NET because its easy to see, change and explain to non programmers; pictures are worth a thousand words as they say!

[1] https://stackoverflow.com/users/448580/remo-gloor
[2] https://stackoverflow.com/users/40516/juliet
[3] https://learn.microsoft.com/en-us/dotnet/framework/windows-workflow-foundation/state-machine-workflows
[4] http://wf.codeplex.com/releases/view/43586

I think the state machine is one of the best parts of the whole workflow foundation! - fabsenet
7
[+8] [2013-11-07 07:14:04] zzfima

Today i deep in State Design Pattern. I did and tested ThreadState, which equal (+/-) to Threading in C#, as described in picture from Threading in C# [1]

enter image description here

You can easly add new states, configure moves from one state to other is very easy becouse it incapsulated in state implementation

Implementation and using at: Implements .NET ThreadState by State Design Pattern [2]

[1] http://www.albahari.com/threading/part2.aspx
[2] https://web.archive.org/web/20140102140708/http://simpledesignpatterns.blogspot.co.il/2013/11/implements-net-threadstate-by-state.html

(2) Link is dead. Do you have another? - rollsch
8
[+8] [2016-04-19 16:16:11] Jet Blue

Found this great tutorial online and it helped me wrap my head around finite state machines.

http://gamedevelopment.tutsplus.com/tutorials/finite-state-machines-theory-and-implementation--gamedev-11867

The tutorial is language agnostic, so it can easily be adapted to your C# needs.

Also, the example used (an ant looking for food) is easy to understand.


From the tutorial:

enter image description here

public class FSM {
    private var activeState :Function; // points to the currently active state function

    public function FSM() {
    }

    public function setState(state :Function) :void {
        activeState = state;
    }

    public function update() :void {
        if (activeState != null) {
            activeState();
        }
    }
}


public class Ant
{
    public var position   :Vector3D;
    public var velocity   :Vector3D;
    public var brain      :FSM;

    public function Ant(posX :Number, posY :Number) {
        position    = new Vector3D(posX, posY);
        velocity    = new Vector3D( -1, -1);
        brain       = new FSM();

        // Tell the brain to start looking for the leaf.
        brain.setState(findLeaf);
    }

    /**
    * The "findLeaf" state.
    * It makes the ant move towards the leaf.
    */
    public function findLeaf() :void {
        // Move the ant towards the leaf.
        velocity = new Vector3D(Game.instance.leaf.x - position.x, Game.instance.leaf.y - position.y);

        if (distance(Game.instance.leaf, this) <= 10) {
            // The ant is extremelly close to the leaf, it's time
            // to go home.
            brain.setState(goHome);
        }

        if (distance(Game.mouse, this) <= MOUSE_THREAT_RADIUS) {
            // Mouse cursor is threatening us. Let's run away!
            // It will make the brain start calling runAway() from
            // now on.
            brain.setState(runAway);
        }
    }

    /**
    * The "goHome" state.
    * It makes the ant move towards its home.
    */
    public function goHome() :void {
        // Move the ant towards home
        velocity = new Vector3D(Game.instance.home.x - position.x, Game.instance.home.y - position.y);

        if (distance(Game.instance.home, this) <= 10) {
            // The ant is home, let's find the leaf again.
            brain.setState(findLeaf);
        }
    }

    /**
    * The "runAway" state.
    * It makes the ant run away from the mouse cursor.
    */
    public function runAway() :void {
        // Move the ant away from the mouse cursor
        velocity = new Vector3D(position.x - Game.mouse.x, position.y - Game.mouse.y);

        // Is the mouse cursor still close?
        if (distance(Game.mouse, this) > MOUSE_THREAT_RADIUS) {
            // No, the mouse cursor has gone away. Let's go back looking for the leaf.
            brain.setState(findLeaf);
        }
    }

    public function update():void {
        // Update the FSM controlling the "brain". It will invoke the currently
        // active state function: findLeaf(), goHome() or runAway().
        brain.update();

        // Apply the velocity vector to the position, making the ant move.
        moveBasedOnVelocity();
    }

    (...)
}

(1) While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review - drneel
@drneel I could copy and paste bits from the tutorial... but would that not be taking credit away from the author? - Jet Blue
(1) @JetBlue: Leave the link in the answer as a reference, and include the relevant bits in your own words in the answer post so as not to break anyone's copyright. I know it seems strict but but many answers have become much, much better because of this rule. - Flimm
9
[+7] [2014-01-27 16:53:39] dluberger

I haven't tried implementing a FSM in C# yet, but these all sound (or look) very complicated to the way I handled FSM's in the past in low-level languages like C or ASM.

I believe the method I've always known is called something like an "Iterative Loop". In it, you essentially have a 'while' loop that periodically exits based on events (interrupts), then returns to the main loop again.

Within the interrupt handlers, you would pass a CurrentState and return a NextState, which then overwrites the CurrentState variable in the main loop. You do this ad infinitum until the program closes (or the microcontroller resets).

What I'm seeing other answers all look very complicated compared with how a FSM is, in my mind, intended to be implemented; its beauty lies in its simplicity and FSM can be very complicated with many, many states and transitions, but they allow complicated process to be easily broken down and digested.

I realize my response shouldn't include another question, but I am forced to ask: why do these other proposed solutions appear to be so complicated?
They seem to be akin to hitting a small nail with a giant sledge hammer.


(1) Completely agree. A simple while loop with a switch statement is as simple as you can get. - rollsch
(3) Unless you have a very complicated state machine with many states and conditions, where you would end up with multiple nested switches. Also there might be a penalty in busy-waiting, depending on your loop implementation. - Sune Rievers
10
[+7] [2020-09-16 19:12:24] Welcor

Not sure whether I miss the point, but I think none of the answers here are "simple" state machines. What i usually call a simple state machine is using a loop with a switch inside. That is what we used in PLC / microchip programming or in C/C++ programming at the university.

advantages:

  • easy to write. no special objects and stuff required. you dont even need object orientation for it.
  • when it is small, it is easy to understand.

disadvantages:

  • can become quite big and hard to read, when there are many states.

It looked like that:

public enum State
{
    First,
    Second,
    Third,
}

static void Main(string[] args)
{
    var state = State.First;
    // x and i are just examples for stuff that you could change inside the state and use for state transitions
    var x     = 0; 
    var i     = 0;

    // does not have to be a while loop. you could loop over the characters of a string too
    while (true)  
    {
        switch (state)
        {
            case State.First:
                // Do sth here
                if (x == 2)
                    state = State.Second;  
                    // you may or may not add a break; right after setting the next state
                // or do sth here
                if (i == 3)
                    state = State.Third;
                // or here
                break;
            case State.Second:
                // Do sth here
                if (x == 10)
                    state = State.First;
                // or do sth here
                break;
            case State.Third:
                // Do sth here
                if (x == 10)
                    state = State.First;
                // or do sth here
                break;
            default:
                // you may wanna throw an exception here.
                break;
        }
    }
}

enter image description here

if it should be really a state machine on which you call methods which react depending on which state you are in differently: state design pattern is the better approach


11
[+5] [2017-11-11 11:51:00] Bizhan

I made this generic state machine out of Juliet's code. It's working awesome for me.

These are the benefits:

  • you can create new state machine in code with two enums TState and TCommand,
  • added struct TransitionResult<TState> to have more control over the output results of [Try]GetNext() methods
  • exposing nested class StateTransition only through AddTransition(TState, TCommand, TState) making it easier to work with it

Code:

public class StateMachine<TState, TCommand>
    where TState : struct, IConvertible, IComparable
    where TCommand : struct, IConvertible, IComparable
{
    protected class StateTransition<TS, TC>
        where TS : struct, IConvertible, IComparable
        where TC : struct, IConvertible, IComparable
    {
        readonly TS CurrentState;
        readonly TC Command;

        public StateTransition(TS currentState, TC command)
        {
            if (!typeof(TS).IsEnum || !typeof(TC).IsEnum)
            {
                throw new ArgumentException("TS,TC must be an enumerated type");
            }

            CurrentState = currentState;
            Command = command;
        }

        public override int GetHashCode()
        {
            return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            StateTransition<TS, TC> other = obj as StateTransition<TS, TC>;
            return other != null
                && this.CurrentState.CompareTo(other.CurrentState) == 0
                && this.Command.CompareTo(other.Command) == 0;
        }
    }

    private Dictionary<StateTransition<TState, TCommand>, TState> transitions;
    public TState CurrentState { get; private set; }

    protected StateMachine(TState initialState)
    {
        if (!typeof(TState).IsEnum || !typeof(TCommand).IsEnum)
        {
            throw new ArgumentException("TState,TCommand must be an enumerated type");
        }

        CurrentState = initialState;
        transitions = new Dictionary<StateTransition<TState, TCommand>, TState>();
    }

    /// <summary>
    /// Defines a new transition inside this state machine
    /// </summary>
    /// <param name="start">source state</param>
    /// <param name="command">transition condition</param>
    /// <param name="end">destination state</param>
    protected void AddTransition(TState start, TCommand command, TState end)
    {
        transitions.Add(new StateTransition<TState, TCommand>(start, command), end);
    }

    public TransitionResult<TState> TryGetNext(TCommand command)
    {
        StateTransition<TState, TCommand> transition = new StateTransition<TState, TCommand>(CurrentState, command);
        TState nextState;
        if (transitions.TryGetValue(transition, out nextState))
            return new TransitionResult<TState>(nextState, true);
        else
            return new TransitionResult<TState>(CurrentState, false);
    }

    public TransitionResult<TState> MoveNext(TCommand command)
    {
        var result = TryGetNext(command);
        if(result.IsValid)
        {
            //changes state
            CurrentState = result.NewState;
        }
        return result;
    }
}

This is the return type of TryGetNext method:

public struct TransitionResult<TState>
{
    public TransitionResult(TState newState, bool isValid)
    {
        NewState = newState;
        IsValid = isValid;
    }
    public TState NewState;
    public bool IsValid;
}

How to use:

This is how you can create a OnlineDiscountStateMachine from the generic class:

Define an enum OnlineDiscountState for its states and an enum OnlineDiscountCommand for its commands.

Define a class OnlineDiscountStateMachine derived from the generic class using those two enums

Derive the constructor from base(OnlineDiscountState.InitialState) so that the initial state is set to OnlineDiscountState.InitialState

Use AddTransition as many times as needed

public class OnlineDiscountStateMachine : StateMachine<OnlineDiscountState, OnlineDiscountCommand>
{
    public OnlineDiscountStateMachine() : base(OnlineDiscountState.Disconnected)
    {
        AddTransition(OnlineDiscountState.Disconnected, OnlineDiscountCommand.Connect, OnlineDiscountState.Connected);
        AddTransition(OnlineDiscountState.Disconnected, OnlineDiscountCommand.Connect, OnlineDiscountState.Error_AuthenticationError);
        AddTransition(OnlineDiscountState.Connected, OnlineDiscountCommand.Submit, OnlineDiscountState.WaitingForResponse);
        AddTransition(OnlineDiscountState.WaitingForResponse, OnlineDiscountCommand.DataReceived, OnlineDiscountState.Disconnected);
    }
}

use the derived state machine

    odsm = new OnlineDiscountStateMachine();
    public void Connect()
    {
        var result = odsm.TryGetNext(OnlineDiscountCommand.Connect);

        //is result valid?
        if (!result.IsValid)
            //if this happens you need to add transitions to the state machine
            //in this case result.NewState is the same as before
            Console.WriteLine("cannot navigate from this state using OnlineDiscountCommand.Connect");

        //the transition was successfull
        //show messages for new states
        else if(result.NewState == OnlineDiscountState.Error_AuthenticationError)
            Console.WriteLine("invalid user/pass");
        else if(result.NewState == OnlineDiscountState.Connected)
            Console.WriteLine("Connected");
        else
            Console.WriteLine("not implemented transition result for " + result.NewState);
    }

12
[+3] [2013-01-21 13:03:04] Bruno Bertechini

What a bout StatePattern. Does that fit your needs?

I think its context related, but its worth a shot for sure.

http://en.wikipedia.org/wiki/State_pattern

This let your states decide where to go and not the "object" class.

Bruno


(1) The state pattern deals with a class that can act differently based on the state/mode it is in, it does not deal with transition between states. - Eli Algranti
13
[+3] [2013-06-14 00:52:12] YSharp

I've just contributed this:

https://code.google.com/p/ysharp/source/browse/#svn%2Ftrunk%2FStateMachinesPoC

Here's one of the examples demoing direct and indirect sending of commands, with states as IObserver(of signal), thus responders to a signal source, IObservable(of signal):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    using Machines;

    public static class WatchingTvSampleAdvanced
    {
        // Enum type for the transition triggers (instead of System.String) :
        public enum TvOperation { Plug, SwitchOn, SwitchOff, Unplug, Dispose }

        // The state machine class type is also used as the type for its possible states constants :
        public class Television : NamedState<Television, TvOperation, DateTime>
        {
            // Declare all the possible states constants :
            public static readonly Television Unplugged = new Television("(Unplugged TV)");
            public static readonly Television Off = new Television("(TV Off)");
            public static readonly Television On = new Television("(TV On)");
            public static readonly Television Disposed = new Television("(Disposed TV)");

            // For convenience, enter the default start state when the parameterless constructor executes :
            public Television() : this(Television.Unplugged) { }

            // To create a state machine instance, with a given start state :
            private Television(Television value) : this(null, value) { }

            // To create a possible state constant :
            private Television(string moniker) : this(moniker, null) { }

            private Television(string moniker, Television value)
            {
                if (moniker == null)
                {
                    // Build the state graph programmatically
                    // (instead of declaratively via custom attributes) :
                    Handler<Television, TvOperation, DateTime> stateChangeHandler = StateChange;
                    Build
                    (
                        new[]
                        {
                            new { From = Television.Unplugged, When = TvOperation.Plug, Goto = Television.Off, With = stateChangeHandler },
                            new { From = Television.Unplugged, When = TvOperation.Dispose, Goto = Television.Disposed, With = stateChangeHandler },
                            new { From = Television.Off, When = TvOperation.SwitchOn, Goto = Television.On, With = stateChangeHandler },
                            new { From = Television.Off, When = TvOperation.Unplug, Goto = Television.Unplugged, With = stateChangeHandler },
                            new { From = Television.Off, When = TvOperation.Dispose, Goto = Television.Disposed, With = stateChangeHandler },
                            new { From = Television.On, When = TvOperation.SwitchOff, Goto = Television.Off, With = stateChangeHandler },
                            new { From = Television.On, When = TvOperation.Unplug, Goto = Television.Unplugged, With = stateChangeHandler },
                            new { From = Television.On, When = TvOperation.Dispose, Goto = Television.Disposed, With = stateChangeHandler }
                        },
                        false
                    );
                }
                else
                    // Name the state constant :
                    Moniker = moniker;
                Start(value ?? this);
            }

            // Because the states' value domain is a reference type, disallow the null value for any start state value : 
            protected override void OnStart(Television value)
            {
                if (value == null)
                    throw new ArgumentNullException("value", "cannot be null");
            }

            // When reaching a final state, unsubscribe from all the signal source(s), if any :
            protected override void OnComplete(bool stateComplete)
            {
                // Holds during all transitions into a final state
                // (i.e., stateComplete implies IsFinal) :
                System.Diagnostics.Debug.Assert(!stateComplete || IsFinal);

                if (stateComplete)
                    UnsubscribeFromAll();
            }

            // Executed before and after every state transition :
            private void StateChange(IState<Television> state, ExecutionStep step, Television value, TvOperation info, DateTime args)
            {
                // Holds during all possible transitions defined in the state graph
                // (i.e., (step equals ExecutionStep.LeaveState) implies (not state.IsFinal))
                System.Diagnostics.Debug.Assert((step != ExecutionStep.LeaveState) || !state.IsFinal);

                // Holds in instance (i.e., non-static) transition handlers like this one :
                System.Diagnostics.Debug.Assert(this == state);

                switch (step)
                {
                    case ExecutionStep.LeaveState:
                        var timeStamp = ((args != default(DateTime)) ? String.Format("\t\t(@ {0})", args) : String.Empty);
                        Console.WriteLine();
                        // 'value' is the state value that we are transitioning TO :
                        Console.WriteLine("\tLeave :\t{0} -- {1} -> {2}{3}", this, info, value, timeStamp);
                        break;
                    case ExecutionStep.EnterState:
                        // 'value' is the state value that we have transitioned FROM :
                        Console.WriteLine("\tEnter :\t{0} -- {1} -> {2}", value, info, this);
                        break;
                    default:
                        break;
                }
            }

            public override string ToString() { return (IsConstant ? Moniker : Value.ToString()); }
        }

        public static void Run()
        {
            Console.Clear();

            // Create a signal source instance (here, a.k.a. "remote control") that implements
            // IObservable<TvOperation> and IObservable<KeyValuePair<TvOperation, DateTime>> :
            var remote = new SignalSource<TvOperation, DateTime>();

            // Create a television state machine instance (automatically set in a default start state),
            // and make it subscribe to a compatible signal source, such as the remote control, precisely :
            var tv = new Television().Using(remote);
            bool done;

            // Always holds, assuming the call to Using(...) didn't throw an exception (in case of subscription failure) :
            System.Diagnostics.Debug.Assert(tv != null, "There's a bug somewhere: this message should never be displayed!");

            // As commonly done, we can trigger a transition directly on the state machine :
            tv.MoveNext(TvOperation.Plug, DateTime.Now);

            // Alternatively, we can also trigger transitions by emitting from the signal source / remote control
            // that the state machine subscribed to / is an observer of :
            remote.Emit(TvOperation.SwitchOn, DateTime.Now);
            remote.Emit(TvOperation.SwitchOff);
            remote.Emit(TvOperation.SwitchOn);
            remote.Emit(TvOperation.SwitchOff, DateTime.Now);

            done =
                (
                    tv.
                        MoveNext(TvOperation.Unplug).
                        MoveNext(TvOperation.Dispose) // MoveNext(...) returns null iff tv.IsFinal == true
                    == null
                );

            remote.Emit(TvOperation.Unplug); // Ignored by the state machine thanks to the OnComplete(...) override above

            Console.WriteLine();
            Console.WriteLine("Is the TV's state '{0}' a final state? {1}", tv.Value, done);

            Console.WriteLine();
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }
}

Note : this example is rather artificial and mostly meant to demo a number of orthogonal features. There should seldomly be a real need to implement the state value domain itself by a full blown class, using the CRTP ( see : http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern ) like this.

Here's for a certainly simpler and likely much more common implementation use case (using a simple enum type as the states value domain), for the same state machine, and with the same test case :

https://code.google.com/p/ysharp/source/browse/trunk/StateMachinesPoC/WatchingTVSample.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    using Machines;

    public static class WatchingTvSample
    {
        public enum Status { Unplugged, Off, On, Disposed }

        public class DeviceTransitionAttribute : TransitionAttribute
        {
            public Status From { get; set; }
            public string When { get; set; }
            public Status Goto { get; set; }
            public object With { get; set; }
        }

        // State<Status> is a shortcut for / derived from State<Status, string>,
        // which in turn is a shortcut for / derived from State<Status, string, object> :
        public class Device : State<Status>
        {
            // Executed before and after every state transition :
            protected override void OnChange(ExecutionStep step, Status value, string info, object args)
            {
                if (step == ExecutionStep.EnterState)
                {
                    // 'value' is the state value that we have transitioned FROM :
                    Console.WriteLine("\t{0} -- {1} -> {2}", value, info, this);
                }
            }

            public override string ToString() { return Value.ToString(); }
        }

        // Since 'Device' has no state graph of its own, define one for derived 'Television' :
        [DeviceTransition(From = Status.Unplugged, When = "Plug", Goto = Status.Off)]
        [DeviceTransition(From = Status.Unplugged, When = "Dispose", Goto = Status.Disposed)]
        [DeviceTransition(From = Status.Off, When = "Switch On", Goto = Status.On)]
        [DeviceTransition(From = Status.Off, When = "Unplug", Goto = Status.Unplugged)]
        [DeviceTransition(From = Status.Off, When = "Dispose", Goto = Status.Disposed)]
        [DeviceTransition(From = Status.On, When = "Switch Off", Goto = Status.Off)]
        [DeviceTransition(From = Status.On, When = "Unplug", Goto = Status.Unplugged)]
        [DeviceTransition(From = Status.On, When = "Dispose", Goto = Status.Disposed)]
        public class Television : Device { }

        public static void Run()
        {
            Console.Clear();

            // Create a television state machine instance, and return it, set in some start state :
            var tv = new Television().Start(Status.Unplugged);
            bool done;

            // Holds iff the chosen start state isn't a final state :
            System.Diagnostics.Debug.Assert(tv != null, "The chosen start state is a final state!");

            // Trigger some state transitions with no arguments
            // ('args' is ignored by this state machine's OnChange(...), anyway) :
            done =
                (
                    tv.
                        MoveNext("Plug").
                        MoveNext("Switch On").
                        MoveNext("Switch Off").
                        MoveNext("Switch On").
                        MoveNext("Switch Off").
                        MoveNext("Unplug").
                        MoveNext("Dispose") // MoveNext(...) returns null iff tv.IsFinal == true
                    == null
                );

            Console.WriteLine();
            Console.WriteLine("Is the TV's state '{0}' a final state? {1}", tv.Value, done);

            Console.WriteLine();
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }
}

'HTH


Isn't it a bit strange that each state instance has its own copy of the state graph? - vgru
@Groo : no, they don't. Only the instances of Television constructed using the private constructor with a null string for the moniker (hence, calling the protected 'Build' method) will have a state graph, as state machines. The others, named instances of Television (with a moniker not null for that conventional and ad-hoc purpose) will be mere "fix point" states (so to speak), serving as the state constants (that the state graph(s) of actual state machines will reference as their vertices). 'HTH, - YSharp
Ok, I get it. Anyway, IMHO, it would've been better if you have included some code which actually handles these transitions. This way, it only serves as an example of using a (IMHO) not-so-obvious interface for your library. For example, how is StateChange resolved? Through Reflection? Is that really necessary? - vgru
(1) @Groo : Good remark. It isn't necessary indeed to reflect on the handler in that first example because it's done programmatically in there precisely and can be statically bound/type checked (unlike when via custom attributes). So this work as expected too: private Television(string moniker, Television value) { Handler<Television, TvOperation, DateTime> myHandler = StateChange; // (code omitted) new { From = Television.Unplugged, When = TvOperation.Plug, Goto = Television.Off, With = myHandler } } - YSharp
@Groo : also, you made a good point regarding my rather contrived examples so far; so, I've just translated both Pete's and Juliet's samples using my generics, if only for getting a gist of the resp. expressiveness differences in implementations, when speaking of the very same test cases; visible here : code.google.com/p/ysharp/source/browse/trunk/StateMachinesPo‌​C/… - YSharp
This seems overcomplicated when a simple Switch statement in a loop would suffice for most cases. I doubt it would be performant either with all the reflection - rollsch
14
[+3] [2016-09-08 06:10:44] Ton Snoei

In my opinion a state machine is not only meant for changing states but also (very important) for handling triggers/events within a specific state. If you want to understand state machine design pattern better, a good description can be found within the book Head First Design Patterns, page 320 [1].

It is not only about the states within variables but also about handling triggers within the different states. Great chapter (and no, there is no fee for me in mentioning this :-) which contains just an easy to understand explanation.

[1] http://shop.oreilly.com/product/9780596007126.do

I think you are confusing 2 concepts. State design pattern vs state machines. Design patterns are more like guidelines how to write good code and state machines are more like mathematical concepts (a.k.a. finite state machines) which can be implemented in various ways. - Johnny
15
[0] [2015-10-13 15:03:56] Domenico Zinzi

FiniteStateMachine is a Simple State Machine, written in C# Link [1]

Advantages tu use my library FiniteStateMachine:

  1. Define a "context" class to present a single interface to the outside world.
  2. Define a State abstract base class.
  3. Represent the different "states" of the state machine as derived classes of the State base class.
  4. Define state-specific behavior in the appropriate State derived classes.
  5. Maintain a pointer to the current "state" in the "context" class.
  6. To change the state of the state machine, change the current "state" pointer.

Download DLL Download [2]

Example on LINQPad:

void Main()
{
            var machine = new SFM.Machine(new StatePaused());
            var output = machine.Command("Input_Start", Command.Start);
            Console.WriteLine(Command.Start.ToString() + "->  State: " + machine.Current);
            Console.WriteLine(output);

            output = machine.Command("Input_Pause", Command.Pause);
            Console.WriteLine(Command.Pause.ToString() + "->  State: " + machine.Current);
            Console.WriteLine(output);
            Console.WriteLine("-------------------------------------------------");
}
    public enum Command
    {
        Start,
        Pause,
    }

    public class StateActive : SFM.State
    {

        public override void Handle(SFM.IContext context)

        {
            //Gestione parametri
            var input = (String)context.Input;
            context.Output = input;

            //Gestione Navigazione
            if ((Command)context.Command == Command.Pause) context.Next = new StatePaused();
            if ((Command)context.Command == Command.Start) context.Next = this;

        }
    }


public class StatePaused : SFM.State
{

     public override void Handle(SFM.IContext context)

     {

         //Gestione parametri
         var input = (String)context.Input;
         context.Output = input;

         //Gestione Navigazione
         if ((Command)context.Command == Command.Start) context.Next = new  StateActive();
         if ((Command)context.Command == Command.Pause) context.Next = this;


     }

 }
[1] https://github.com/thedom85/CSharp_FiniteStateMachine
[2] https://github.com/thedom85/CSharp_FiniteStateMachine/blob/master/SFM/SFM/bin/Debug/SFM.dll

(2) It has GNU GPL license. - Der_Meister
16
[0] [2015-10-22 13:24:34] bmorin

I would recommend state.cs [1]. I personally used state.js (the JavaScript version) and am very happy with it. That C# version works in a similar way.

You instantiate states:

        // create the state machine
        var player = new StateMachine<State>( "player" );

        // create some states
        var initial = player.CreatePseudoState( "initial", PseudoStateKind.Initial );
        var operational = player.CreateCompositeState( "operational" );
        ...

You instantiate some transitions:

        var t0 = player.CreateTransition( initial, operational );
        player.CreateTransition( history, stopped );
        player.CreateTransition<String>( stopped, running, ( state, command ) => command.Equals( "play" ) );
        player.CreateTransition<String>( active, stopped, ( state, command ) => command.Equals( "stop" ) );

You define actions on states and transitions:

    t0.Effect += DisengageHead;
    t0.Effect += StopMotor;

And that's (pretty much) it. Look at the website for more information.

[1] http://steelbreeze.net/state.cs/

17
[0] [2017-03-16 05:34:44] Der_Meister

There are 2 popular state machine packages in NuGet.

Appccelerate.StateMachine [1] (13.6K downloads + 3.82K of legacy version (bbv.Common.StateMachine))

StateMachineToolkit [2] (1.56K downloads)

The Appccelerate lib has good documentation [3], but it does not support .NET 4, so I chose StateMachineToolkit for my project.

[1] https://github.com/appccelerate/statemachine
[2] https://github.com/OmerMor/StateMachineToolkit
[3] http://www.appccelerate.com/statemachine.html

18
[0] [2019-07-30 15:55:30] mcdm

Other alternative in this repo https://github.com/lingkodsoft/StateBliss used fluent syntax, supports triggers.

    public class BasicTests
    {
        [Fact]
        public void Tests()
        {
            // Arrange
            StateMachineManager.Register(new [] { typeof(BasicTests).Assembly }); //Register at bootstrap of your application, i.e. Startup
            var currentState = AuthenticationState.Unauthenticated;
            var nextState = AuthenticationState.Authenticated;
            var data = new Dictionary<string, object>();

            // Act
            var changeInfo = StateMachineManager.Trigger(currentState, nextState, data);

            // Assert
            Assert.True(changeInfo.StateChangedSucceeded);
            Assert.Equal("ChangingHandler1", changeInfo.Data["key1"]);
            Assert.Equal("ChangingHandler2", changeInfo.Data["key2"]);
        }

        //this class gets regitered automatically by calling StateMachineManager.Register
        public class AuthenticationStateDefinition : StateDefinition<AuthenticationState>
        {
            public override void Define(IStateFromBuilder<AuthenticationState> builder)
            {
                builder.From(AuthenticationState.Unauthenticated).To(AuthenticationState.Authenticated)
                    .Changing(this, a => a.ChangingHandler1)
                    .Changed(this, a => a.ChangedHandler1);

                builder.OnEntering(AuthenticationState.Authenticated, this, a => a.OnEnteringHandler1);
                builder.OnEntered(AuthenticationState.Authenticated, this, a => a.OnEnteredHandler1);

                builder.OnExiting(AuthenticationState.Unauthenticated, this, a => a.OnExitingHandler1);
                builder.OnExited(AuthenticationState.Authenticated, this, a => a.OnExitedHandler1);

                builder.OnEditing(AuthenticationState.Authenticated, this, a => a.OnEditingHandler1);
                builder.OnEdited(AuthenticationState.Authenticated, this, a => a.OnEditedHandler1);

                builder.ThrowExceptionWhenDiscontinued = true;
            }

            private void ChangingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
                var data = changeinfo.DataAs<Dictionary<string, object>>();
                data["key1"] = "ChangingHandler1";
            }

            private void OnEnteringHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
                // changeinfo.Continue = false; //this will prevent changing the state
            }

            private void OnEditedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {                
            }

            private void OnExitedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {                
            }

            private void OnEnteredHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {                
            }

            private void OnEditingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
            }

            private void OnExitingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
            }

            private void ChangedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {
            }
        }

        public class AnotherAuthenticationStateDefinition : StateDefinition<AuthenticationState>
        {
            public override void Define(IStateFromBuilder<AuthenticationState> builder)
            {
                builder.From(AuthenticationState.Unauthenticated).To(AuthenticationState.Authenticated)
                    .Changing(this, a => a.ChangingHandler2);

            }

            private void ChangingHandler2(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
                var data = changeinfo.DataAs<Dictionary<string, object>>();
                data["key2"] = "ChangingHandler2";
            }
        }
    }

    public enum AuthenticationState
    {
        Unauthenticated,
        Authenticated
    }
}


19
[0] [2021-03-24 23:46:33] Ian Mercer

One more state machine for the list, mine: https://github.com/IanMercer/Abodit.StateMachine

In addition to simple states with entry and exit actions, and actions on each transition, this one is designed for use in async code. It also supports hierarchical states and compound state machines. So not really 'simple' but in use it's quite easy to code states and transitions.

static OpenClosedStateMachine()
{
    Closed
       .When(Fridge.eDoorOpens, (m, s, e, c) => Task.FromResult(Open));

    Open
        .When(Fridge.eDoorCloses, (m, s, e, c) => Task.FromResult(Closed));
}

Unlike others it also supports temporal transitions so it's easy to transition to a different state After a given period or At a given time.


20
[0] [2023-01-05 06:12:38] Ahmed Abuelnour

I've built a Nuget library that implements a simple and powerful state machine and injectable in DI. You can check it from here Nuget - State Machine [1]

[1] https://www.nuget.org/packages/Flaminco.StateMachine

21
[-1] [2020-06-22 23:08:14] GMIKE

You can use my solution, this is the most convenient way. It’s also free.

Create state machine in three steps :

1. Create scheme in node editor🔗 [1] and load it in your project using library📚 [2]

StateMachine stateMachine = new StateMachine("scheme.xml");

2. Describe your app logic on events⚡

stateMachine.GetState("State1").OnExit(Action1);
stateMachine.GetState("State2").OnEntry(Action2);
stateMachine.GetTransition("Transition1").OnInvoke(Action3);
stateMachine.OnChangeState(Action4);

3. Run the state machine🚘

stateMachine.Start();

Links:

Node editor: https://github.com/SimpleStateMachine/SimpleStateMachineNodeEditor

Library: https://github.com/SimpleStateMachine/SimpleStateMachineLibrary

[1] https://github.com/SimpleStateMachine/SimpleStateMachineNodeEditor
[2] https://github.com/SimpleStateMachine/SimpleStateMachineLibrary

22