This little project was born from an old (but good) state machine written in C++, with the goal to improve it and make it object-oriented and suited for a .NET application.
Special thanks to the stateless project, that helped me pretty much.
StateMachine has a simple workflow. It requires the definition of states, transitions between them and actions which can be performed when entering or exiting a state and when going from one to another.
The example below describes a three-states machine with trasitions from/to the next one.
enum States
{
R,
G,
B
}
StateMachine<States> machine = new StateMachine<States>();
machine.AddState(States.R);
machine.AddState(States.G);
machine.AddState(States.B);
machine.AddTransition(States.R, States.G);
machine.AddTransition(States.R, States.B);
machine.AddTransition(States.G, States.R);
machine.AddTransition(States.G, States.B);
machine.AddTransition(States.B, States.R);
machine.AddTransition(States.B, States.G);
machine.AddEnterStateCallback(States.R, (state) => Console.WriteLine("Entering state {0}", state));
machine.AddEnterStateCallback(States.G, (state) => Console.WriteLine("Entering state {0}", state));
machine.AddEnterStateCallback(States.B, (state) => Console.WriteLine("Entering state {0}", state));
machine.AddExitStateCallback(States.R, (state) => Console.WriteLine("Exiting state {0}", state));
machine.AddExitStateCallback(States.G, (state) => Console.WriteLine("Exiting state {0}", state));
machine.AddExitStateCallback(States.B, (state) => Console.WriteLine("Exiting state {0}", state));
machine.AddTransitionCallback(States.R, States.G, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
machine.AddTransitionCallback(States.R, States.B, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
machine.AddTransitionCallback(States.G, States.R, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
machine.AddTransitionCallback(States.G, States.B, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
machine.AddTransitionCallback(States.B, States.R, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
machine.AddTransitionCallback(States.B, States.G, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
StateMachine<States> machine = new StateMachine<States>();
When declaring, StateMachine accepts an enum that indicates the states type.
machine.AddState(States.R);
Call the AddState()
method to add the state to the machine.
machine.AddTransition(States.R, States.G);
Call the AddTransition()
method to add a new transition between two states.
The actions performed by StateMachine can be defined using delegates. They will be kept in memory by StateMachine and executed when desired.
machine.AddEnterStateCallback(States.R, (state) => Console.WriteLine("Entering state {0}", state));
machine.AddExitStateCallback(States.R, (state) => Console.WriteLine("Exiting state {0}", state));
machine.AddTransitionCallback(States.R, States.G, (from, to) => Console.WriteLine("Going from {0} to {1}", from, to));
The two state methods want the related state or states followed by the delegate. The first one accept the target state as a parameter, while the transition method wants the source state and the target one.
To keep track of what happens inside StateMachine, two event handlers have been implemented, Transiting and Transited.
machine.Transiting += new EventHandler<TransitingEventArgs<States>>(TransitingEventHandler);
machine.Transited += new EventHandler<TransitedEventArgs<States>>(callbacks.TransitedEventHandler);
...
private void TransitingEventHandler(object sender, TransitingEventArgs e)
{
Console.WriteLine("Event fired: Transiting into state {0}", e.State);
}
private void TransitedEventHandler(object sender, TransitedEventArgs e)
{
Console.WriteLine("Event fired: Transited into state {0}", e.State);
}
The transiting event fires before the exiting callbacks, while the Transited one is fired at the end of the process (after the entering callbacks).