diff --git a/src/PersistenceExample/App.config b/src/PersistenceExample/App.config
new file mode 100644
index 0000000..343984d
--- /dev/null
+++ b/src/PersistenceExample/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/PersistenceExample/PersistenceExample.csproj b/src/PersistenceExample/PersistenceExample.csproj
new file mode 100644
index 0000000..e29df7e
--- /dev/null
+++ b/src/PersistenceExample/PersistenceExample.csproj
@@ -0,0 +1,64 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {3C45B29F-222C-4914-A4F8-3775438A4070}
+ Exe
+ Properties
+ PersistenceExample
+ PersistenceExample
+ v3.5
+ 512
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {a15eec02-60ec-4705-a58b-a6ecd55a9628}
+ Stateless
+
+
+
+
+
\ No newline at end of file
diff --git a/src/PersistenceExample/Program.cs b/src/PersistenceExample/Program.cs
new file mode 100644
index 0000000..01542ca
--- /dev/null
+++ b/src/PersistenceExample/Program.cs
@@ -0,0 +1,51 @@
+using System;
+using Stateless;
+
+namespace PersistenceExample
+{
+ static class Program
+ {
+ static void Main()
+ {
+ try
+ {
+ const string on = "On";
+ const string off = "Off";
+ const char space = ' ';
+
+ Console.WriteLine("Press to toggle the switch. Any other key will raise an error.");
+
+ var savedState = off;
+ Func loadMethod = () =>
+ {
+ Console.WriteLine("(Persistence: state {0} has been loaded)", savedState);
+ return savedState;
+ };
+ Action saveMethod = state =>
+ {
+ savedState = state;
+ Console.WriteLine("(Persistence: state {0} has been saved)", state);
+ };
+
+ var initialState = loadMethod();
+ var onOffSwitch = new StateMachine(initialState, saveMethod);
+
+ onOffSwitch.Configure(off).Permit(space, on);
+ onOffSwitch.Configure(on).Permit(space, off);
+
+ while (true)
+ {
+ Console.WriteLine("Switch is in state: " + onOffSwitch.State);
+ var pressed = Console.ReadKey(true).KeyChar;
+ onOffSwitch.Fire(pressed);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Exception: " + ex.Message);
+ Console.WriteLine("Press any key to continue...");
+ Console.ReadKey(true);
+ }
+ }
+ }
+}
diff --git a/src/PersistenceExample/Properties/AssemblyInfo.cs b/src/PersistenceExample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..6684b51
--- /dev/null
+++ b/src/PersistenceExample/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("PersistenceExample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("PersistenceExample")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2a02c2e2-2c9a-433f-8e35-1e1e72e3625c")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Stateless.Tests/StateMachineFixture.cs b/src/Stateless.Tests/StateMachineFixture.cs
index 4cc5d7b..99f2e70 100755
--- a/src/Stateless.Tests/StateMachineFixture.cs
+++ b/src/Stateless.Tests/StateMachineFixture.cs
@@ -66,6 +66,31 @@ public void StateCanBeStoredExternally()
Assert.AreEqual(State.C, state);
}
+ [Test]
+ public void StateIsWrittenJustOnceOnEveryStateTransition()
+ {
+ var state = State.B;
+ var saveCount = 0;
+ Action stateMutator = s =>
+ {
+ saveCount++;
+ state = s;
+ };
+ var sm = new StateMachine(State.B, stateMutator);
+ sm.Configure(State.B).Permit(Trigger.X, State.C);
+ sm.Configure(State.C).Permit(Trigger.Y, State.B);
+ Assert.AreEqual(State.B, sm.State);
+ Assert.AreEqual(State.B, state);
+ sm.Fire(Trigger.X);
+ Assert.AreEqual(State.C, sm.State);
+ Assert.AreEqual(State.C, state);
+ Assert.AreEqual(1, saveCount);
+ sm.Fire(Trigger.Y);
+ Assert.AreEqual(State.B, sm.State);
+ Assert.AreEqual(State.B, state);
+ Assert.AreEqual(2, saveCount);
+ }
+
[Test]
public void SubstateIsIncludedInCurrentState()
{
diff --git a/src/Stateless.sln b/src/Stateless.sln
index 307b401..e34f1db 100755
--- a/src/Stateless.sln
+++ b/src/Stateless.sln
@@ -1,6 +1,8 @@
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stateless", "Stateless\Stateless.csproj", "{A15EEC02-60EC-4705-A58B-A6ECD55A9628}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stateless.Tests", "Stateless.Tests\Stateless.Tests.csproj", "{70AD8860-1F5E-4F78-9276-CAD498EDDF73}"
@@ -11,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TelephoneCallExample", "Tel
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugTrackerExample", "BugTrackerExample\BugTrackerExample.csproj", "{3A56311E-C3AC-4E34-A1DF-CA5042A31039}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersistenceExample", "PersistenceExample\PersistenceExample.csproj", "{3C45B29F-222C-4914-A4F8-3775438A4070}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -37,6 +41,10 @@ Global
{3A56311E-C3AC-4E34-A1DF-CA5042A31039}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A56311E-C3AC-4E34-A1DF-CA5042A31039}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A56311E-C3AC-4E34-A1DF-CA5042A31039}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3C45B29F-222C-4914-A4F8-3775438A4070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C45B29F-222C-4914-A4F8-3775438A4070}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C45B29F-222C-4914-A4F8-3775438A4070}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C45B29F-222C-4914-A4F8-3775438A4070}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Stateless/StateMachine.cs b/src/Stateless/StateMachine.cs
index beecc6e..984ba80 100755
--- a/src/Stateless/StateMachine.cs
+++ b/src/Stateless/StateMachine.cs
@@ -39,6 +39,22 @@ public StateMachine(TState initialState)
_stateMutator = s => reference.State = s;
}
+ ///
+ /// Construct a state machine with external storage (saving only).
+ ///
+ /// The initial state.
+ /// An action that will be called to write new state values.
+ public StateMachine(TState initialState, Action stateMutator)
+ {
+ var reference = new StateReference { State = initialState };
+ _stateAccessor = () => reference.State;
+ _stateMutator = s =>
+ {
+ reference.State = s;
+ stateMutator(s);
+ };
+ }
+
///
/// The current state.
///