I am using stateless and have the following states:
When the fault trigger happens, I want the state machine to transition to the Faulted state, regardless of the previous state. Is there a way to do that something like:
machine.RegisterGlobalTrigger(Trigger.Fault, State.Faulted)
Note: I have thought of the following options, but looking for a "cleaner" solution:
It isn't as pretty as the one-liner, but you could use a List of all possible states as a way of setting global or semi-global configuration, like:
Enum.GetValues<State>()
.Where(state => state != State.Faulted) // so we don't put a Faulted .Permit() on the Faulted State
.ToList()
.ForEach(state =>
{
stateMachine.Configure(state)
.Permit(Trigger.Fault, State.Faulted);
});
Example with testing in this dotnet fiddle demo.
Full example code:
using System;
using System.Linq;
using Stateless;
public class Program
{
public enum State
{
Foo,
Bar,
Faulted
}
public enum Trigger
{
Fooify,
Barify,
Fault
}
public static void Main()
{
// setup
var stateMachine = new StateMachine<State, Trigger>(State.Faulted);
stateMachine.Configure(State.Foo)
.Permit(Trigger.Barify, State.Bar);
stateMachine.Configure(State.Bar)
.Permit(Trigger.Fooify, State.Foo);
stateMachine.Configure(State.Faulted)
.Permit(Trigger.Fooify, State.Foo)
.Permit(Trigger.Barify, State.Bar);
Enum.GetValues<State>()
.Where(state => state != State.Faulted) // so we don't put a Faulted .Permit() on the Faulted State
.ToList()
.ForEach(state =>
{
stateMachine.Configure(state)
.Permit(Trigger.Fault, State.Faulted);
});
// using the same pattern to add transition logging to every state
Enum.GetValues<State>()
.ToList()
.ForEach(state =>
{
stateMachine.Configure(state)
.OnEntry(t => Console.WriteLine($"Entering {t.Destination} from {t.Source}"));
});
// testing
// To Foo, then to Faulted
stateMachine.Fire(Trigger.Fooify);
stateMachine.Fire(Trigger.Fault);
// To Bar, then to Faulted
stateMachine.Fire(Trigger.Barify);
stateMachine.Fire(Trigger.Fault);
Console.WriteLine("Done.");
}
}