This repository was archived by the owner on Mar 4, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathStateMachine.cs
More file actions
105 lines (86 loc) · 3.56 KB
/
Copy pathStateMachine.cs
File metadata and controls
105 lines (86 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
using StateMachine.Core.EventArgs;
using StateMachine.Core.Exceptions;
namespace StateMachine.Core
{
public class StateMachine<TState> where TState : notnull
{
private readonly Dictionary<TState, State<TState>> _statesMap = new();
private State<TState> this[TState state]
{
get
{
if (!_statesMap.ContainsKey(state))
{
throw new StateMachineException<TState>(ErrorCodes.StateNotFound, state);
}
return _statesMap[state];
}
}
public bool IsTransiting { get; private set; }
public TState CurrentState { get; private set; }
public event EventHandler<TransitingEventArgs<TState>> Transiting = delegate { };
public event EventHandler<TransitedEventArgs<TState>> Transited = delegate { };
protected virtual void OnTransiting(TransitingEventArgs<TState> e) => Transiting?.Invoke(this, e);
protected virtual void OnTransited(TransitedEventArgs<TState> e) => Transited?.Invoke(this, e);
public StateMachine(TState currentState)
{
IsTransiting = false;
CurrentState = currentState;
AddState(currentState);
}
public void AddState(TState stateName)
{
if (_statesMap.ContainsKey(stateName))
{
throw new StateMachineException<TState>(ErrorCodes.StateAlreadyAdded, stateName);
}
State<TState> state = new(stateName);
_statesMap[stateName] = state;
}
public void AddArc(TState source, TState target)
{
State<TState> sourceState = this[source];
State<TState> targetState = this[target];
sourceState.AddArc(targetState);
}
public void AddEnterStateCallback(TState targetStateName, Func<TState, Task> callback)
{
State<TState> targetState = this[targetStateName];
targetState.AddStateCallback(callback, true);
}
public void AddExitStateCallback(TState targetStateName, Func<TState, Task> callback)
{
State<TState> targetState = this[targetStateName];
targetState.AddStateCallback(callback, false);
}
public void AddArcCallback(TState source, TState target, Func<TState, TState, Task> callback)
{
State<TState> state = this[source];
state.AddArcCallback(target, callback);
}
public async Task GoToStateAsync(TState targetState)
{
try
{
if (IsTransiting)
{
throw new StateMachineException<TState>(ErrorCodes.AlreadyTransiting, targetState);
}
IsTransiting = true;
OnTransiting(new TransitingEventArgs<TState>(targetState));
State<TState> currentStateWrapper = this[CurrentState];
Arc<TState> arc = currentStateWrapper[targetState];
await currentStateWrapper.InvokeExitCallbacksAsync().ConfigureAwait(false);
await arc.InvokeAllCallbacksAsync().ConfigureAwait(false);
CurrentState = targetState;
State<TState> targetStateWrapper = this[targetState];
await targetStateWrapper.InvokeEnterCallbacksAsync().ConfigureAwait(false);
OnTransited(new TransitedEventArgs<TState>(CurrentState));
}
finally
{
IsTransiting = false;
}
}
}
}