DSeries.DStateMachine.Core
1.0.0
See the version list below for details.
dotnet add package DSeries.DStateMachine.Core --version 1.0.0
NuGet\Install-Package DSeries.DStateMachine.Core -Version 1.0.0
<PackageReference Include="DSeries.DStateMachine.Core" Version="1.0.0" />
<PackageVersion Include="DSeries.DStateMachine.Core" Version="1.0.0" />
<PackageReference Include="DSeries.DStateMachine.Core" />
paket add DSeries.DStateMachine.Core --version 1.0.0
#r "nuget: DSeries.DStateMachine.Core, 1.0.0"
#addin nuget:?package=DSeries.DStateMachine.Core&version=1.0.0
#tool nuget:?package=DSeries.DStateMachine.Core&version=1.0.0
DStateMachine
DStateMachine is a powerful and flexible asynchronous state machine library for .NET, designed with a clean, fluent API and production-ready architecture. It supports dynamic transitions, guard conditions, entry/exit hooks, and internal transitions, making it ideal for complex stateful workflows.
✨ Features
- Generic Support: Works with any type for states and triggers (e.g.,
string
,int
,enum
). - Fluent API: Concise and expressive DSL for configuration.
- Asynchronous Execution: Seamless async/await support for transitions and actions.
- Entry and Exit Hooks: Configure entry/exit actions per state.
- Guard Clauses: Conditionally block transitions.
- Internal Transitions: Perform side-effect actions without state change.
- Dynamic Transitions: Determine the destination state at runtime.
- DOT Export: Generate DOT-format graphs for visualization.
📚 Example Usage
var sm = new DStateMachine<string, string>("A");
sm.Configure("A")
.OnEntry(() => Console.WriteLine("Entering A"))
.OnExit(() => Console.WriteLine("Exiting A"))
.OnTrigger("toB", tb => tb.ChangeState("B"));
sm.Configure("B").OnEntry(() => Console.WriteLine("Entered B"));
await sm.FireAsync("toB");
Console.WriteLine(sm.CurrentState); // Output: B
✅ Feature Examples
✅ Generic Type Support
var sm = new DStateMachine<int, int>(0);
sm.Configure(0).OnTrigger(1, tb => tb.ChangeState(2));
sm.Fire(1);
Console.WriteLine(sm.CurrentState); // Output: 2
🔁 Entry and Exit Actions
var sm = new DStateMachine<string, string>("Init");
bool entered = false, exited = false;
sm.Configure("Init")
.OnEntry(() => { entered = true; return Task.CompletedTask; })
.OnExit(() => { exited = true; return Task.CompletedTask; })
.OnTrigger("go", tb => tb.ChangeState("Done"));
sm.Configure("Done").OnEntry(() => Task.CompletedTask);
sm.Fire("go");
Console.WriteLine($"Entered: {entered}, Exited: {exited}"); // Output: Entered: False, Exited: True
⛔ Guard Clauses
var sm = new DStateMachine<string, string>("A");
sm.Configure("A")
.OnTrigger("toB", tb => tb.ChangeState("B").If(() => false));
sm.OnUnhandledTrigger((trigger, machine) => {
Console.WriteLine("Blocked by guard");
return Task.CompletedTask;
});
sm.Fire("toB"); // Output: Blocked by guard
⏳ Asynchronous Transitions
var sm = new DStateMachine<string, string>("Start");
sm.Configure("Start")
.OnTrigger("load", tb => tb.ChangeStateAsync(async () => {
await Task.Delay(100);
return "Loaded";
}));
sm.Configure("Loaded").OnEntry(() => Task.CompletedTask);
await sm.FireAsync("load");
Console.WriteLine(sm.CurrentState); // Output: Loaded
🧠 Dynamic Transitions
var sm = new DStateMachine<string, string>("A");
sm.Configure("A")
.OnTrigger("toNext", tb => tb.ChangeState(() => DateTime.Now.Second % 2 == 0 ? "Even" : "Odd"));
sm.Configure("Even").OnEntry(() => Task.CompletedTask);
sm.Configure("Odd").OnEntry(() => Task.CompletedTask);
sm.Fire("toNext");
Console.WriteLine(sm.CurrentState); // Output: "Even" or "Odd"
🔁 Internal Transitions
var sm = new DStateMachine<string, string>("Idle");
bool logged = false;
sm.Configure("Idle")
.OnTrigger("ping", tb => tb.ExecuteAction(() => logged = true));
await sm.FireAsync("ping");
Console.WriteLine($"State: {sm.CurrentState}, Logged: {logged}");
// Output: State: Idle, Logged: True
💬 Fluent DSL
var sm = new DStateMachine<string, string>("X");
sm.Configure("X")
.OnTrigger("a", tb => tb.ChangeState("A"))
.OnTrigger("b", tb => tb.ChangeState("B"));
Console.WriteLine(sm.Configure("X").Machine == sm); // Output: True
📈 DOT Graph Export
var sm = new DStateMachine<string, string>("Start");
sm.Configure("Start").OnTrigger("toEnd", tb => tb.ChangeState("End"));
sm.Configure("End").OnEntry(() => Task.CompletedTask);
string dot = sm.ExportToDot();
Console.WriteLine(dot);
// Output: DOT-format string of the state machine
🎓 Getting Started
- Clone the repository or add the files to your project.
- Create a new instance:
new DStateMachine<TTrigger, TState>(initialState)
. - Configure states using
.Configure(state)
and chainOnEntry
,OnExit
, andOnTrigger
. - Fire transitions using
Fire(trigger)
orawait FireAsync(trigger)
.
🙌 Contributions
Pull requests and issues are welcome! If you'd like to contribute improvements or new features, feel free to fork and open a PR.
📄 License
This project is licensed under the MIT License.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial release of DStateMachine.Core with support for guard conditions, dynamic transitions, and entry/exit actions.