Skip to content

Commit c4c6caa

Browse files
committed
Make Transition Actions Async-First
Pull request dotnet-state-machine#452
1 parent a8c8fe0 commit c4c6caa

20 files changed

+641
-794
lines changed

src/Stateless/ActivateActionBehaviour.cs

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,34 @@ namespace Stateless;
66

77
public partial class StateMachine<TState, TTrigger>
88
{
9-
internal abstract class ActivateActionBehaviour
9+
internal class ActivateActionBehaviour
1010
{
11-
private readonly TState _state;
11+
private readonly TState _state;
1212

13-
private ActivateActionBehaviour(TState state, InvocationInfo actionDescription)
14-
{
15-
_state = state;
16-
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
17-
}
13+
private readonly EventCallback _callback = EventCallbackFactory.Empty;
1814

1915
internal InvocationInfo Description { get; }
2016

21-
public abstract void Execute();
22-
public abstract Task ExecuteAsync();
17+
public ActivateActionBehaviour(TState state, Action action, InvocationInfo actionDescription)
18+
: this(state, actionDescription) {
19+
_callback = EventCallbackFactory.Create(action);
20+
}
2321

24-
public class Sync : ActivateActionBehaviour
22+
public ActivateActionBehaviour(TState state, Func<Task> action, InvocationInfo actionDescription)
23+
: this(state, actionDescription)
2524
{
26-
private readonly Action _action;
27-
28-
public Sync(TState state, Action action, InvocationInfo actionDescription)
29-
: base(state, actionDescription)
30-
{
31-
_action = action;
32-
}
33-
34-
public override void Execute()
35-
{
36-
_action();
37-
}
38-
39-
public override Task ExecuteAsync()
40-
{
41-
Execute();
42-
return TaskResult.Done;
43-
}
25+
_callback = EventCallbackFactory.Create(action);
4426
}
4527

46-
public class Async : ActivateActionBehaviour
28+
protected ActivateActionBehaviour(TState state, InvocationInfo actionDescription)
4729
{
48-
private readonly Func<Task> _action;
49-
50-
public Async(TState state, Func<Task> action, InvocationInfo actionDescription)
51-
: base(state, actionDescription)
52-
{
53-
_action = action;
54-
}
55-
56-
public override void Execute()
57-
{
58-
throw new InvalidOperationException(
59-
$"Cannot execute asynchronous action specified in OnActivateAsync for '{_state}' state. Use asynchronous version of Activate [ActivateAsync]");
60-
}
30+
_state = state;
31+
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
32+
}
6133

62-
public override Task ExecuteAsync()
63-
{
64-
return _action();
65-
}
34+
public virtual Task ExecuteAsync()
35+
{
36+
return _callback.InvokeAsync();
6637
}
6738
}
6839
}

src/Stateless/DeactivateActionBehaviour.cs

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,35 @@ namespace Stateless;
66

77
public partial class StateMachine<TState, TTrigger>
88
{
9-
internal abstract class DeactivateActionBehaviour
9+
internal class DeactivateActionBehaviour
1010
{
11-
private readonly TState _state;
12-
13-
private DeactivateActionBehaviour(TState state, InvocationInfo actionDescription)
14-
{
15-
_state = state;
16-
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
17-
}
11+
private readonly TState _state;
12+
13+
private readonly EventCallback _callback = EventCallbackFactory.Empty;
1814

1915
internal InvocationInfo Description { get; }
2016

21-
public abstract void Execute();
22-
public abstract Task ExecuteAsync();
17+
public DeactivateActionBehaviour(TState state, Action action, InvocationInfo actionDescription)
18+
: this(state, actionDescription) {
19+
_callback = EventCallbackFactory.Create(action);
20+
}
2321

24-
public class Sync : DeactivateActionBehaviour
22+
public DeactivateActionBehaviour(TState state, Func<Task> action, InvocationInfo actionDescription)
23+
: this(state, actionDescription)
2524
{
26-
private readonly Action _action;
27-
28-
public Sync(TState state, Action action, InvocationInfo actionDescription)
29-
: base(state, actionDescription)
30-
{
31-
_action = action;
32-
}
33-
34-
public override void Execute()
35-
{
36-
_action();
37-
}
38-
39-
public override Task ExecuteAsync()
40-
{
41-
Execute();
42-
return TaskResult.Done;
43-
}
25+
_callback = EventCallbackFactory.Create(action);
4426
}
4527

46-
public class Async : DeactivateActionBehaviour
28+
protected DeactivateActionBehaviour(TState state, InvocationInfo actionDescription)
4729
{
48-
private readonly Func<Task> _action;
49-
50-
public Async(TState state, Func<Task> action, InvocationInfo actionDescription)
51-
: base(state, actionDescription)
52-
{
53-
_action = action;
54-
}
55-
56-
public override void Execute()
57-
{
58-
throw new InvalidOperationException(
59-
$"Cannot execute asynchronous action specified in OnDeactivateAsync for '{_state}' state. Use asynchronous version of Deactivate [DeactivateAsync]");
60-
}
30+
_state = state;
31+
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
32+
}
6133

62-
public override Task ExecuteAsync()
63-
{
64-
return _action();
65-
}
34+
public virtual Task ExecuteAsync()
35+
{
36+
return _callback.InvokeAsync();
6637
}
38+
6739
}
6840
}

src/Stateless/EntryActionBehaviour.cs

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,81 +6,56 @@ namespace Stateless;
66

77
public partial class StateMachine<TState, TTrigger>
88
{
9-
internal abstract class EntryActionBehavior
9+
internal class EntryActionBehavior
1010
{
11-
private EntryActionBehavior(InvocationInfo description)
11+
private readonly EventCallback<Transition, object?[]> _callback = EventCallbackFactory.Create<Transition, object?[]>(delegate { });
12+
13+
public EntryActionBehavior(Action<Transition, object?[]> action, InvocationInfo description)
14+
: this(description)
1215
{
13-
Description = description;
16+
_callback = EventCallbackFactory.Create(action);
1417
}
1518

16-
public InvocationInfo Description { get; }
17-
18-
public abstract void Execute(Transition transition, object?[] args);
19-
public abstract Task ExecuteAsync(Transition transition, object?[] args);
20-
21-
public class Sync : EntryActionBehavior
19+
public EntryActionBehavior(Func<Transition, object?[], Task> action, InvocationInfo description)
20+
: this(description)
2221
{
23-
private readonly Action<Transition, object?[]> _action;
22+
_callback = EventCallbackFactory.Create(action);
23+
}
2424

25-
public Sync(Action<Transition, object?[]> action, InvocationInfo description) : base(description)
26-
{
27-
_action = action;
28-
}
25+
protected EntryActionBehavior(InvocationInfo description)
26+
{
27+
Description = description;
28+
}
2929

30-
public override void Execute(Transition transition, object?[] args)
31-
{
32-
_action(transition, args);
33-
}
30+
public InvocationInfo Description { get; }
3431

35-
public override Task ExecuteAsync(Transition transition, object?[] args)
36-
{
37-
Execute(transition, args);
38-
return TaskResult.Done;
39-
}
32+
public virtual Task ExecuteAsync(Transition transition, object?[] args)
33+
{
34+
return _callback.InvokeAsync(transition, args);
4035
}
4136

42-
public class SyncFrom<TTriggerType> : Sync
37+
public class From<TTriggerType> : EntryActionBehavior
4338
{
4439
internal TTriggerType Trigger { get; }
4540

46-
public SyncFrom(TTriggerType trigger, Action<Transition, object?[]> action, InvocationInfo description)
41+
public From(TTriggerType trigger, Action<Transition, object?[]> action, InvocationInfo description)
4742
: base(action, description)
4843
{
4944
Trigger = trigger;
5045
}
5146

52-
public override void Execute(Transition transition, object?[] args)
47+
public From(TTriggerType trigger, Func<Transition, object?[], Task> action, InvocationInfo description)
48+
: base(action, description)
5349
{
54-
if (transition.Trigger.Equals(Trigger))
55-
base.Execute(transition, args);
50+
Trigger = trigger;
5651
}
5752

5853
public override Task ExecuteAsync(Transition transition, object?[] args)
5954
{
60-
Execute(transition, args);
55+
if (transition.Trigger.Equals(Trigger))
56+
return base.ExecuteAsync(transition, args);
6157
return TaskResult.Done;
6258
}
6359
}
64-
65-
public class Async : EntryActionBehavior
66-
{
67-
private readonly Func<Transition, object?[], Task> _action;
68-
69-
public Async(Func<Transition, object?[], Task> action, InvocationInfo description) : base(description)
70-
{
71-
_action = action;
72-
}
73-
74-
public override void Execute(Transition transition, object?[] args)
75-
{
76-
throw new InvalidOperationException(
77-
$"Cannot execute asynchronous action specified in OnEntry event for '{transition.Destination}' state. Use asynchronous version of Fire [FireAsync]");
78-
}
79-
80-
public override Task ExecuteAsync(Transition transition, object?[] args)
81-
{
82-
return _action(transition, args);
83-
}
84-
}
8560
}
8661
}

0 commit comments

Comments
 (0)