Skip to content

Commit 7a9f121

Browse files
author
Cesar Romero Silva
committed
+ StateMachine examples (not really related right now, but it may be)
1 parent 80ecc68 commit 7a9f121

8 files changed

+503
-9
lines changed

BulkOperation.cs

+15
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
using System;
22
using System.Data.SqlClient;
3+
using System.Diagnostics;
34
using System.Threading;
45
using System.Threading.Tasks;
56

67
namespace BulkOperations
78
{
89
public static class BulkOperation
910
{
11+
public static void Run()
12+
{
13+
var stopwatch = new Stopwatch();
14+
stopwatch.Start();
15+
16+
ConsoleLog.Write("Início processamento");
17+
18+
BulkOperation.InsertAsync().Wait();
19+
20+
stopwatch.Stop();
21+
22+
ConsoleLog.Write($"Processamento concluído em {stopwatch.ElapsedTimeFmt()}");
23+
}
24+
1025
public static async Task InsertAsync(CancellationToken cancellationToken = default(CancellationToken))
1126
{
1227
using (var connection = new SqlConnection())

BulkOperations.csproj

+11
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333
<WarningLevel>4</WarningLevel>
3434
</PropertyGroup>
3535
<ItemGroup>
36+
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
37+
<HintPath>packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
38+
</Reference>
39+
<Reference Include="Stateless, Version=4.0.0.0, Culture=neutral, PublicKeyToken=93038f0927583c9a, processorArchitecture=MSIL">
40+
<HintPath>packages\Stateless.4.2.1\lib\net45\Stateless.dll</HintPath>
41+
</Reference>
3642
<Reference Include="System" />
3743
<Reference Include="System.Configuration" />
3844
<Reference Include="System.Core" />
@@ -44,6 +50,7 @@
4450
<Reference Include="System.Xml" />
4551
</ItemGroup>
4652
<ItemGroup>
53+
<Compile Include="StateMachineBug.cs" />
4754
<Compile Include="BulkOperation.cs" />
4855
<Compile Include="BulkUpdate.cs" />
4956
<Compile Include="ConsoleLog.cs" />
@@ -53,11 +60,15 @@
5360
<Compile Include="Program.cs" />
5461
<Compile Include="Properties\AssemblyInfo.cs" />
5562
<Compile Include="SqlConnectionExtension.cs" />
63+
<Compile Include="StateMachineMember.cs" />
64+
<Compile Include="StateMachineOnOff.cs" />
65+
<Compile Include="StateMachinePhoneCall.cs" />
5666
<Compile Include="StopwatchExtension.cs" />
5767
<Compile Include="Todo.cs" />
5868
</ItemGroup>
5969
<ItemGroup>
6070
<None Include="App.config" />
71+
<None Include="packages.config" />
6172
</ItemGroup>
6273
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
6374
</Project>

Program.cs

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
using System;
2-
using System.Diagnostics;
32

43
namespace BulkOperations
54
{
65
internal static class Program
76
{
87
private static void Main(string[] args)
98
{
10-
var stopwatch = new Stopwatch();
11-
stopwatch.Start();
9+
//Console.WriteLine("BUG");
10+
//StateMachineBug.Run();
1211

13-
ConsoleLog.Write("Início processamento");
12+
//Console.WriteLine("\nMEMBER");
13+
//StateMachineMember.Run();
1414

15-
BulkOperation.InsertAsync().Wait();
15+
//Console.WriteLine("\nON/OFF");
16+
//StateMachineOnOff.Run();
1617

17-
stopwatch.Stop();
18+
//Console.WriteLine("\nPHONE CALL");
19+
//StateMachinePhoneCall.Run();
1820

19-
20-
ConsoleLog.Write($"Processamento concluído em {stopwatch.ElapsedTimeFmt()}");
21+
BulkOperation.Run();
2122

2223
Console.WriteLine("");
2324
Console.WriteLine("Tecle <ENTER> para finalizar...");
24-
Console.ReadLine();
25+
Console.ReadKey(false);
2526
}
2627
}
2728
}

StateMachineBug.cs

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using System;
2+
using Stateless;
3+
using Stateless.Graph;
4+
5+
namespace BulkOperations
6+
{
7+
public class StateMachineBug
8+
{
9+
public static void Run()
10+
{
11+
var bug = new StateMachineBug("Incorrect stock count");
12+
13+
bug.Assign("Joe");
14+
bug.Defer();
15+
bug.Assign("Harry");
16+
bug.Assign("Fred");
17+
bug.Close();
18+
19+
Console.WriteLine();
20+
Console.WriteLine("State machine:");
21+
Console.WriteLine(bug.ToDotGraph());
22+
}
23+
24+
private enum State
25+
{
26+
Open,
27+
Assigned,
28+
Deferred,
29+
Closed
30+
}
31+
32+
private enum Trigger
33+
{
34+
Assign,
35+
Defer,
36+
Close
37+
}
38+
39+
private readonly StateMachine<State, Trigger> _machine;
40+
41+
// The TriggerWithParameters object is used when a trigger requires a payload.
42+
private readonly StateMachine<State, Trigger>.TriggerWithParameters<string> _assignTrigger;
43+
44+
private readonly string _title;
45+
46+
private string _assignee;
47+
48+
49+
/// <summary>
50+
/// Constructor for the Bug class
51+
/// </summary>
52+
/// <param name="title">The title of the bug report</param>
53+
public StateMachineBug(string title)
54+
{
55+
_title = title;
56+
57+
// Instantiate a new state machine in the Open state
58+
_machine = new StateMachine<State, Trigger>(State.Open);
59+
60+
// Instantiate a new trigger with a parameter.
61+
_assignTrigger = _machine.SetTriggerParameters<string>(Trigger.Assign);
62+
63+
// Configure the Open state
64+
_machine.Configure(State.Open)
65+
.Permit(Trigger.Assign, State.Assigned);
66+
67+
// Configure the Assigned state
68+
_machine.Configure(State.Assigned)
69+
.SubstateOf(State.Open)
70+
.OnEntryFrom(_assignTrigger, OnAssigned) // This is where the TriggerWithParameters is used. Note that the TriggerWithParameters object is used, not something from the enum
71+
.PermitReentry(Trigger.Assign)
72+
.Permit(Trigger.Close, State.Closed)
73+
.Permit(Trigger.Defer, State.Deferred)
74+
.OnExit(OnDeassigned);
75+
76+
// Configure the Deferred state
77+
_machine.Configure(State.Deferred)
78+
.OnEntry(() => _assignee = null)
79+
.Permit(Trigger.Assign, State.Assigned);
80+
}
81+
82+
public void Close()
83+
{
84+
_machine.Fire(Trigger.Close);
85+
}
86+
87+
public void Assign(string assignee)
88+
{
89+
// This is how a trigger with parameter is used, the parameter is supplied to the state machine as a parameter to the Fire method.
90+
_machine.Fire(_assignTrigger, assignee);
91+
}
92+
93+
public bool CanAssign => _machine.CanFire(Trigger.Assign);
94+
95+
public void Defer()
96+
{
97+
_machine.Fire(Trigger.Defer);
98+
}
99+
/// <summary>
100+
/// This method is called automatically when the Assigned state is entered, but only when the trigger is _assignTrigger.
101+
/// </summary>
102+
/// <param name="assignee"></param>
103+
private void OnAssigned(string assignee)
104+
{
105+
if (_assignee != null && assignee != _assignee)
106+
SendEmailToAssignee("Don't forget to help the new employee!");
107+
108+
_assignee = assignee;
109+
SendEmailToAssignee("You own it.");
110+
}
111+
/// <summary>
112+
/// This method is called when the state machinie exits the Assigned state
113+
/// </summary>
114+
private void OnDeassigned()
115+
{
116+
SendEmailToAssignee("You're off the hook.");
117+
}
118+
119+
private void SendEmailToAssignee(string message)
120+
{
121+
// ReSharper disable once LocalizableElement
122+
Console.WriteLine("{0}, RE {1}: {2}", _assignee, _title, message);
123+
}
124+
125+
public string ToDotGraph()
126+
{
127+
return UmlDotGraph.Format(_machine.GetInfo());
128+
}
129+
}
130+
}

StateMachineMember.cs

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System;
2+
using Newtonsoft.Json;
3+
using Stateless;
4+
5+
namespace BulkOperations
6+
{
7+
public class StateMachineMember
8+
{
9+
public static void Run()
10+
{
11+
Console.WriteLine("Creating member from JSON");
12+
var member = FromJson("{ \"State\":\"1\",\"Name\":\"Jay\"}");
13+
14+
Console.WriteLine($"Member {member.Name} created, membership state is {member.State}");
15+
16+
member.Suspend();
17+
member.Reactivate();
18+
member.Terminate();
19+
20+
Console.WriteLine("Member JSON:");
21+
22+
var jsonString = member.ToJson();
23+
Console.WriteLine(jsonString);
24+
25+
var anotherMember = FromJson(jsonString);
26+
27+
if (member.Equals(anotherMember))
28+
{
29+
Console.WriteLine("Members are equal");
30+
}
31+
}
32+
33+
private enum MemberTriggers
34+
{
35+
Suspend,
36+
Terminate,
37+
Reactivate
38+
}
39+
public enum MembershipState
40+
{
41+
Inactive,
42+
Active,
43+
Terminated
44+
}
45+
public MembershipState State => _stateMachine.State;
46+
public string Name { get; }
47+
48+
private readonly StateMachine<MembershipState, MemberTriggers> _stateMachine;
49+
50+
public StateMachineMember(string name)
51+
{
52+
_stateMachine = new StateMachine<MembershipState, MemberTriggers>(MembershipState.Active);
53+
Name = name;
54+
55+
ConfigureStateMachine();
56+
}
57+
58+
[JsonConstructor]
59+
private StateMachineMember(string state, string name)
60+
{
61+
var memberState = (MembershipState)Enum.Parse(typeof(MembershipState), state);
62+
_stateMachine = new StateMachine<MembershipState, MemberTriggers>(memberState);
63+
Name = name;
64+
65+
ConfigureStateMachine();
66+
}
67+
68+
private void ConfigureStateMachine()
69+
{
70+
_stateMachine.Configure(MembershipState.Active)
71+
.Permit(MemberTriggers.Suspend, MembershipState.Inactive)
72+
.Permit(MemberTriggers.Terminate, MembershipState.Terminated);
73+
74+
_stateMachine.Configure(MembershipState.Inactive)
75+
.Permit(MemberTriggers.Reactivate, MembershipState.Active)
76+
.Permit(MemberTriggers.Terminate, MembershipState.Terminated);
77+
78+
_stateMachine.Configure(MembershipState.Terminated)
79+
.Permit(MemberTriggers.Reactivate, MembershipState.Active);
80+
}
81+
82+
public void Terminate()
83+
{
84+
_stateMachine.Fire(MemberTriggers.Terminate);
85+
}
86+
87+
public void Suspend()
88+
{
89+
_stateMachine.Fire(MemberTriggers.Suspend);
90+
}
91+
92+
public void Reactivate()
93+
{
94+
_stateMachine.Fire(MemberTriggers.Reactivate);
95+
}
96+
97+
public string ToJson()
98+
{
99+
return JsonConvert.SerializeObject(this);
100+
}
101+
102+
public static StateMachineMember FromJson(string jsonString)
103+
{
104+
return JsonConvert.DeserializeObject<StateMachineMember>(jsonString);
105+
}
106+
107+
public bool Equals(StateMachineMember anotherMember)
108+
{
109+
return (State == anotherMember.State) && (Name == anotherMember.Name);
110+
}
111+
}
112+
}

StateMachineOnOff.cs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
3+
using Stateless;
4+
5+
namespace BulkOperations
6+
{
7+
public static class StateMachineOnOff
8+
{
9+
public static void Run()
10+
{
11+
const string on = "On";
12+
const string off = "Off";
13+
const char space = ' ';
14+
15+
// Instantiate a new state machine in the 'off' state
16+
var onOffSwitch = new StateMachine<string, char>(off);
17+
18+
// Configure state machine with the Configure method, supplying the state to be configured as a parameter
19+
onOffSwitch.Configure(off).Permit(space, on);
20+
onOffSwitch.Configure(on).Permit(space, off);
21+
22+
Console.WriteLine("Press <space> to toggle the switch. Any other key will exit the program.");
23+
24+
while (true)
25+
{
26+
Console.WriteLine("Switch is in state: " + onOffSwitch.State);
27+
var pressed = Console.ReadKey(true).KeyChar;
28+
29+
// Check if user wants to exit
30+
if (pressed != space) break;
31+
32+
// Use the Fire method with the trigger as payload to supply the state machine with an event.
33+
// The state machine will react according to its configuration.
34+
onOffSwitch.Fire(pressed);
35+
}
36+
}
37+
38+
}
39+
}

0 commit comments

Comments
 (0)