Skip to content

Commit eb1bec5

Browse files
committed
Make Transition Actions Async-First
Pull request dotnet-state-machine#452
1 parent 8029b18 commit eb1bec5

20 files changed

+655
-795
lines changed

Diff for: src/Stateless/ActivateActionBehaviour.cs

+17-46
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,34 @@ namespace Stateless;
44

55
public partial class StateMachine<TState, TTrigger>
66
{
7-
internal abstract class ActivateActionBehaviour
7+
internal class ActivateActionBehaviour
88
{
9-
private readonly TState _state;
9+
private readonly TState _state;
1010

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

1713
internal InvocationInfo Description { get; }
1814

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

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

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

60-
public override Task ExecuteAsync()
61-
{
62-
return _action();
63-
}
32+
public virtual Task ExecuteAsync()
33+
{
34+
return _callback.InvokeAsync();
6435
}
6536
}
6637
}

Diff for: src/Stateless/DeactivateActionBehaviour.cs

+19-47
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,35 @@ namespace Stateless;
44

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

1713
internal InvocationInfo Description { get; }
1814

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

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

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

60-
public override Task ExecuteAsync()
61-
{
62-
return _action();
63-
}
32+
public virtual Task ExecuteAsync()
33+
{
34+
return _callback.InvokeAsync();
6435
}
36+
6537
}
6638
}

Diff for: src/Stateless/EntryActionBehaviour.cs

+25-50
Original file line numberDiff line numberDiff line change
@@ -4,81 +4,56 @@ namespace Stateless;
44

55
public partial class StateMachine<TState, TTrigger>
66
{
7-
internal abstract class EntryActionBehavior
7+
internal class EntryActionBehavior
88
{
9-
private EntryActionBehavior(InvocationInfo description)
9+
private readonly EventCallback<Transition, object?[]> _callback = EventCallbackFactory.Create<Transition, object?[]>(delegate { });
10+
11+
public EntryActionBehavior(Action<Transition, object?[]> action, InvocationInfo description)
12+
: this(description)
1013
{
11-
Description = description;
14+
_callback = EventCallbackFactory.Create(action);
1215
}
1316

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

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

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

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

40-
public class SyncFrom<TTriggerType> : Sync
35+
public class From<TTriggerType> : EntryActionBehavior
4136
{
4237
internal TTriggerType Trigger { get; }
4338

44-
public SyncFrom(TTriggerType trigger, Action<Transition, object?[]> action, InvocationInfo description)
39+
public From(TTriggerType trigger, Action<Transition, object?[]> action, InvocationInfo description)
4540
: base(action, description)
4641
{
4742
Trigger = trigger;
4843
}
4944

50-
public override void Execute(Transition transition, object?[] args)
45+
public From(TTriggerType trigger, Func<Transition, object?[], Task> action, InvocationInfo description)
46+
: base(action, description)
5147
{
52-
if (transition.Trigger.Equals(Trigger))
53-
base.Execute(transition, args);
48+
Trigger = trigger;
5449
}
5550

5651
public override Task ExecuteAsync(Transition transition, object?[] args)
5752
{
58-
Execute(transition, args);
53+
if (transition.Trigger.Equals(Trigger))
54+
return base.ExecuteAsync(transition, args);
5955
return TaskResult.Done;
6056
}
6157
}
62-
63-
public class Async : EntryActionBehavior
64-
{
65-
private readonly Func<Transition, object?[], Task> _action;
66-
67-
public Async(Func<Transition, object?[], Task> action, InvocationInfo description) : base(description)
68-
{
69-
_action = action;
70-
}
71-
72-
public override void Execute(Transition transition, object?[] args)
73-
{
74-
throw new InvalidOperationException(
75-
$"Cannot execute asynchronous action specified in OnEntry event for '{transition.Destination}' state. Use asynchronous version of Fire [FireAsync]");
76-
}
77-
78-
public override Task ExecuteAsync(Transition transition, object?[] args)
79-
{
80-
return _action(transition, args);
81-
}
82-
}
8358
}
8459
}

0 commit comments

Comments
 (0)