你是否遇到过这样的开发噩梦:一个设备管理系统,设备有启动、运行、暂停、故障等十几种状态,状态间的转换规则复杂,用if-else写了几百行代码,每次新增需求都要小心翼翼地修改多个地方,生怕影响到其他功能?
或者在开发订单系统、游戏角色管理时,状态转换逻辑散落在各个方法中,维护起来痛不欲生?
今天就来彻底解决这个问题!我将通过一个完整的工业设备管理系统案例,从零开始教你用Stateless状态机库构建优雅、可维护的状态管理方案。不仅有理论讲解,更有可直接使用的生产级代码模板。
首先通过NuGet安装Stateless库:
bashInstall-Package Stateless
核心概念解析:
Configure(): 配置特定状态的转换规则Permit(): 允许从当前状态通过指定指令转换到目标状态Fire(): 触发状态转换痛点一:状态转换逻辑散乱
c#// 传统做法:状态逻辑分散在各处
public class DeviceManager
{
private DeviceState _state = DeviceState.Stopped;
public void StartDevice()
{
if (_state == DeviceState.Stopped)
{
_state = DeviceState.Starting;
// 启动逻辑...
}
else if (_state == DeviceState.Paused)
{
_state = DeviceState.Running;
// 恢复逻辑...
}
// 还有更多if-else...
}
public void StopDevice()
{
if (_state == DeviceState.Running || _state == DeviceState.Paused)
{
_state = DeviceState.Stopping;
// 停止逻辑...
}
// 又是一堆判断...
}
}
痛点二:新增状态影响全局
每次新增一个状态,都要:
痛点三:状态转换规则不清晰
✅ 声明式配置:一次配置,处处使用
✅ 自动验证:非法转换自动拦截
✅ 事件驱动:完美支持异步处理
✅ 高性能:零运行时反射,性能出色
c#// 安装NuGet包:Install-Package Stateless
using Stateless;
// 1. 定义状态和触发器
public enum DeviceState { Stopped, Starting, Running, Stopping }
public enum DeviceCommand { Start, Stop, Complete }
// 2. 创建状态机
var machine = new StateMachine<DeviceState, DeviceCommand>(DeviceState.Stopped);
// 3. 配置转换规则
machine.Configure(DeviceState.Stopped)
.Permit(DeviceCommand.Start, DeviceState.Starting);
machine.Configure(DeviceState.Starting)
.Permit(DeviceCommand.Complete, DeviceState.Running);
// 4. 执行转换
machine.Fire(DeviceCommand.Start); // Stopped -> Starting
关键优势:配置与使用分离,规则清晰明了,维护成本大幅降低!
现在我们构建一个完整的工业设备管理系统,包含WinForms界面和复杂的状态管理逻辑。

c#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppIndustrialStateMachine.Models
{
/// <summary>
/// 设备状态枚举
/// </summary>
public enum DeviceState
{
/// <summary>停机状态</summary>
Stopped,
/// <summary>启动中</summary>
Starting,
/// <summary>运行中</summary>
Running,
/// <summary>暂停中</summary>
Pausing,
/// <summary>已暂停</summary>
Paused,
/// <summary>停止中</summary>
Stopping,
/// <summary>故障状态</summary>
Faulted,
/// <summary>维护模式</summary>
Maintenance,
/// <summary>急停状态</summary>
EmergencyStop
}
/// <summary>
/// 设备指令枚举
/// </summary>
public enum DeviceCommand
{
/// <summary>启动指令</summary>
Start,
/// <summary>停止指令</summary>
Stop,
/// <summary>暂停指令</summary>
Pause,
/// <summary>恢复指令</summary>
Resume,
/// <summary>重置指令</summary>
Reset,
/// <summary>急停指令</summary>
EmergencyStop,
/// <summary>维护模式</summary>
EnterMaintenance,
/// <summary>退出维护</summary>
ExitMaintenance,
/// <summary>故障确认</summary>
AcknowledgeFault
}
}
c#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AppIndustrialStateMachine.Models;
using Stateless;
namespace AppIndustrialStateMachine.StateMachine
{
/// <summary>
/// 设备状态机管理器
/// </summary>
public class DeviceStateMachine
{
private readonly StateMachine<DeviceState, DeviceCommand> _machine;
private readonly StateMachine<DeviceState, DeviceCommand>.TriggerWithParameters<string> _faultTrigger;
// 添加内部状态追踪
private bool _isStartingComplete = false;
private bool _isPausingComplete = false;
private bool _isStoppingComplete = false;
private readonly Random _random = new Random();
public event EventHandler<StateTransitionEventArgs> StateChanged;
public event EventHandler<string> LogMessage;
public DeviceState CurrentState => _machine.State;
public DeviceStateMachine()
{
_machine = new StateMachine<DeviceState, DeviceCommand>(DeviceState.Stopped);
_faultTrigger = _machine.SetTriggerParameters<string>(DeviceCommand.AcknowledgeFault);
ConfigureStateMachine();
}
/// <summary>
/// 配置状态机转换规则 - 修复版本
/// </summary>
private void ConfigureStateMachine()
{
// 停机状态 -> 启动/维护/急停
_machine.Configure(DeviceState.Stopped)
.Permit(DeviceCommand.Start, DeviceState.Starting)
.Permit(DeviceCommand.EnterMaintenance, DeviceState.Maintenance)
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.OnEntry(OnStateStopped);
// 启动中状态 - 修复守护条件逻辑
_machine.Configure(DeviceState.Starting)
.Permit(DeviceCommand.Stop, DeviceState.Stopping)
.PermitIf(DeviceCommand.Start, DeviceState.Running, () => _isStartingComplete) // 使用内部标志
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.OnEntry(OnStateStarting)
.OnExit(OnExitStarting);
// 运行中状态
_machine.Configure(DeviceState.Running)
.Permit(DeviceCommand.Pause, DeviceState.Pausing)
.Permit(DeviceCommand.Stop, DeviceState.Stopping)
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.PermitDynamic(DeviceCommand.AcknowledgeFault, () => DeviceState.Faulted)
.OnEntry(OnStateRunning)
.OnExit(OnExitRunning);
// 暂停中状态 - 修复守护条件
_machine.Configure(DeviceState.Pausing)
.PermitIf(DeviceCommand.Pause, DeviceState.Paused, () => _isPausingComplete) // 使用内部标志
.Permit(DeviceCommand.Resume, DeviceState.Running)
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.OnEntry(OnStatePausing);
// 已暂停状态
_machine.Configure(DeviceState.Paused)
.Permit(DeviceCommand.Resume, DeviceState.Running)
.Permit(DeviceCommand.Stop, DeviceState.Stopping)
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.OnEntry(OnStatePaused);
// 停止中状态 - 修复守护条件
_machine.Configure(DeviceState.Stopping)
.PermitIf(DeviceCommand.Stop, DeviceState.Stopped, () => _isStoppingComplete) // 使用内部标志
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.OnEntry(OnStateStopping);
// 故障状态
_machine.Configure(DeviceState.Faulted)
.Permit(DeviceCommand.Reset, DeviceState.Stopped)
.Permit(DeviceCommand.EnterMaintenance, DeviceState.Maintenance)
.Permit(DeviceCommand.EmergencyStop, DeviceState.EmergencyStop)
.OnEntry(OnStateFaulted);
// 维护模式
_machine.Configure(DeviceState.Maintenance)
.Permit(DeviceCommand.ExitMaintenance, DeviceState.Stopped)
.OnEntry(OnStateMaintenance);
// 急停状态
_machine.Configure(DeviceState.EmergencyStop)
.Permit(DeviceCommand.Reset, DeviceState.Stopped)
.OnEntry(OnStateEmergencyStop);
// 全局状态变化事件
_machine.OnTransitioned(OnStateTransitioned);
}
/// <summary>
/// 触发状态转换 - 增强错误处理
/// </summary>
public bool TryFireCommand(DeviceCommand command, string parameter = null)
{
try
{
// 检查当前状态是否允许该指令
if (!_machine.PermittedTriggers.Contains(command))
{
LogMessage?.Invoke(this, $"当前状态 [{GetStateDisplayName(_machine.State)}] 不允许执行指令: {GetCommandDisplayName(command)}");
return false;
}
if (parameter != null && command == DeviceCommand.AcknowledgeFault)
{
_machine.Fire(_faultTrigger, parameter);
}
else
{
_machine.Fire(command);
}
return true;
}
catch (InvalidOperationException ex)
{
LogMessage?.Invoke(this, $"状态转换失败: {ex.Message}");
return false;
}
catch (Exception ex)
{
LogMessage?.Invoke(this, $"状态转换异常: {ex.Message}");
return false;
}
}
/// <summary>
/// 获取当前状态允许的指令
/// </summary>
public DeviceCommand[] GetPermittedCommands()
{
return _machine.PermittedTriggers.ToArray();
}
#region 状态进入事件 - 修复异步处理
private void OnStateStopped()
{
// 重置所有状态标志
_isStartingComplete = false;
_isPausingComplete = false;
_isStoppingComplete = false;
LogMessage?.Invoke(this, "设备已停止");
}
private void OnStateStarting()
{
LogMessage?.Invoke(this, "设备启动中...");
_isStartingComplete = false;
// 使用更可靠的异步启动过程
StartStartupProcess();
}
private void OnStateRunning()
{
LogMessage?.Invoke(this, "设备正在运行");
_isStartingComplete = false; // 重置启动完成标志
}
private void OnStatePausing()
{
LogMessage?.Invoke(this, "设备暂停中...");
_isPausingComplete = false;
// 启动暂停过程
StartPausingProcess();
}
private void OnStatePaused()
{
LogMessage?.Invoke(this, "设备已暂停");
_isPausingComplete = false; // 重置暂停完成标志
}
private void OnStateStopping()
{
LogMessage?.Invoke(this, "设备停止中...");
_isStoppingComplete = false;
// 启动停止过程
StartStoppingProcess();
}
private void OnStateFaulted()
{
LogMessage?.Invoke(this, "设备故障!");
}
private void OnStateMaintenance()
{
LogMessage?.Invoke(this, "进入维护模式");
}
private void OnStateEmergencyStop()
{
LogMessage?.Invoke(this, "紧急停止!");
}
private void OnExitStarting()
{
LogMessage?.Invoke(this, "启动过程完成");
}
private void OnExitRunning()
{
LogMessage?.Invoke(this, "退出运行状态");
}
#endregion
#region 异步状态处理方法
/// <summary>
/// 启动启动过程
/// </summary>
private async void StartStartupProcess()
{
try
{
// 模拟启动过程,包含随机因素
await Task.Delay(2000);
// 模拟启动成功检查(90% 成功率)
bool startupSuccess = _random.Next(1, 101) <= 90;
if (startupSuccess && _machine.State == DeviceState.Starting)
{
_isStartingComplete = true;
LogMessage?.Invoke(this, "启动过程完成,准备进入运行状态");
// 自动转换到运行状态
TryFireCommand(DeviceCommand.Start);
}
else if (_machine.State == DeviceState.Starting)
{
LogMessage?.Invoke(this, "启动失败,设备返回停止状态");
TryFireCommand(DeviceCommand.Stop);
}
}
catch (Exception ex)
{
LogMessage?.Invoke(this, $"启动过程异常: {ex.Message}");
}
}
/// <summary>
/// 启动暂停过程
/// </summary>
private async void StartPausingProcess()
{
try
{
await Task.Delay(1000);
if (_machine.State == DeviceState.Pausing)
{
_isPausingComplete = true;
LogMessage?.Invoke(this, "暂停过程完成");
TryFireCommand(DeviceCommand.Pause);
}
}
catch (Exception ex)
{
LogMessage?.Invoke(this, $"暂停过程异常: {ex.Message}");
}
}
/// <summary>
/// 启动停止过程
/// </summary>
private async void StartStoppingProcess()
{
try
{
await Task.Delay(1500);
if (_machine.State == DeviceState.Stopping)
{
_isStoppingComplete = true;
LogMessage?.Invoke(this, $"停止过程完成");
TryFireCommand(DeviceCommand.Stop);
}
}
catch (Exception ex)
{
LogMessage?.Invoke(this, $"停止过程异常: {ex.Message}");
}
}
#endregion
#region 辅助方法
/// <summary>
/// 获取状态显示名称
/// </summary>
private string GetStateDisplayName(DeviceState state)
{
return state switch
{
DeviceState.Stopped => "停机",
DeviceState.Starting => "启动中",
DeviceState.Running => "运行中",
DeviceState.Pausing => "暂停中",
DeviceState.Paused => "已暂停",
DeviceState.Stopping => "停止中",
DeviceState.Faulted => "故障",
DeviceState.Maintenance => "维护",
DeviceState.EmergencyStop => "急停",
_ => state.ToString()
};
}
/// <summary>
/// 获取指令显示名称
/// </summary>
private string GetCommandDisplayName(DeviceCommand command)
{
return command switch
{
DeviceCommand.Start => "启动",
DeviceCommand.Stop => "停止",
DeviceCommand.Pause => "暂停",
DeviceCommand.Resume => "恢复",
DeviceCommand.Reset => "重置",
DeviceCommand.EmergencyStop => "急停",
DeviceCommand.EnterMaintenance => "进入维护",
DeviceCommand.ExitMaintenance => "退出维护",
DeviceCommand.AcknowledgeFault => "故障确认",
_ => command.ToString()
};
}
#endregion
private void OnStateTransitioned(StateMachine<DeviceState, DeviceCommand>.Transition transition)
{
StateChanged?.Invoke(this, new StateTransitionEventArgs
{
FromState = transition.Source,
ToState = transition.Destination,
Command = transition.Trigger,
Timestamp = DateTime.Now
});
}
}
/// <summary>
/// 状态转换事件参数
/// </summary>
public class StateTransitionEventArgs : EventArgs
{
public DeviceState FromState { get; set; }
public DeviceState ToState { get; set; }
public DeviceCommand Command { get; set; }
public DateTime Timestamp { get; set; }
}
}
c#/// <summary>
/// 主窗体 - 状态机与UI完美结合的示范
/// </summary>
public partial class MainForm : Form
{
private DeviceStateMachine _stateMachine;
private int _productionCount = 0;
private void InitializeSystem()
{
// 初始化状态机
_stateMachine = new DeviceStateMachine();
_stateMachine.StateChanged += OnStateChanged;
_stateMachine.LogMessage += OnLogMessage;
// 更新初始界面状态
UpdateUI();
}
/// <summary>
/// 状态变化处理 - 关键的UI同步逻辑
/// </summary>
private void OnStateChanged(object sender, StateTransitionEventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action(() => OnStateChanged(sender, e)));
return;
}
// 立即更新按钮状态 - 防止用户误操作
UpdateButtonStates();
// 更新状态显示
UpdateStatusDisplay(e);
// 记录状态转换日志
LogStateTransition(e);
}
/// <summary>
/// 实时按钮状态更新 - 解决UI同步问题的核心方法
/// </summary>
private void UpdateButtonStates()
{
var permittedCommands = _stateMachine.GetPermittedCommands();
var currentState = _stateMachine.CurrentState;
// 根据允许的指令更新按钮
btnStart.Enabled = permittedCommands.Contains(DeviceCommand.Start);
btnStop.Enabled = permittedCommands.Contains(DeviceCommand.Stop);
btnPause.Enabled = permittedCommands.Contains(DeviceCommand.Pause);
btnResume.Enabled = permittedCommands.Contains(DeviceCommand.Resume);
btnReset.Enabled = permittedCommands.Contains(DeviceCommand.Reset);
btnEmergencyStop.Enabled = permittedCommands.Contains(DeviceCommand.EmergencyStop);
// 视觉反馈增强
UpdateButtonVisualFeedback(currentState);
}
/// <summary>
/// 按钮视觉反馈 - 让用户清楚知道当前状态
/// </summary>
private void UpdateButtonVisualFeedback(DeviceState state)
{
// 重置所有按钮样式
ResetButtonStyles();
// 根据状态设置特殊样式
switch (state)
{
case DeviceState.Starting:
btnStart.BackColor = Color.Orange;
btnStart.Text = "🔄 启动中";
break;
case DeviceState.Running:
btnStart.BackColor = Color.Green;
btnStart.Text = "✅ 运行中";
break;
case DeviceState.Stopping:
btnStop.BackColor = Color.Orange;
btnStop.Text = "🔄 停止中";
break;
case DeviceState.Pausing:
btnPause.BackColor = Color.Orange;
btnPause.Text = "🔄 暂停中";
break;
case DeviceState.Faulted:
btnReset.BackColor = Color.Red;
btnReset.Text = "🔧 故障重置";
break;
}
}
/// <summary>
/// 统一的指令执行方法 - 包含防重复点击保护
/// </summary>
private void ExecuteCommand(DeviceCommand command, string commandName)
{
// 临时禁用所有按钮,防止快速重复点击
SetAllButtonsEnabled(false);
try
{
bool success = _stateMachine.TryFireCommand(command);
if (!success)
{
// 显示错误信息
ShowCommandError(command, commandName);
}
}
finally
{
// 延迟重新启用按钮
Task.Delay(200).ContinueWith(_ =>
{
if (InvokeRequired)
Invoke(new Action(UpdateButtonStates));
else
UpdateButtonStates();
});
}
}
#region 按钮事件处理
private void BtnStart_Click(object sender, EventArgs e)
{
ExecuteCommand(DeviceCommand.Start, "启动");
}
private void BtnStop_Click(object sender, EventArgs e)
{
ExecuteCommand(DeviceCommand.Stop, "停止");
}
private void BtnPause_Click(object sender, EventArgs e)
{
ExecuteCommand(DeviceCommand.Pause, "暂停");
}
private void BtnEmergencyStop_Click(object sender, EventArgs e)
{
ExecuteCommand(DeviceCommand.EmergencyStop, "急停");
// 急停后的特殊处理
if (_stateMachine.CurrentState == DeviceState.EmergencyStop)
{
MessageBox.Show("紧急停止已激活!请检查设备后重置。",
"紧急停止", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
#endregion
}


c#// ❌ 错误做法:使用随机或不确定的条件
.PermitIf(DeviceCommand.Start, DeviceState.Running, () => Random.Next() > 0.5)
// ✅ 正确做法:使用明确的状态标志
private bool _isStartupComplete = false;
.PermitIf(DeviceCommand.Start, DeviceState.Running, () => _isStartupComplete)
关键点:守护条件必须是确定性的,避免使用随机数或外部不可控因素。
c#private async void OnStateStarting()
{
try
{
_isStartingComplete = false;
// 执行异步操作
await PerformStartupAsync();
// 重要:检查状态是否仍然有效
if (_machine.State == DeviceState.Starting)
{
_isStartingComplete = true;
TryFireCommand(DeviceCommand.Start);
}
}
catch (Exception ex)
{
// 异常处理
HandleStartupError(ex);
}
}
常见坑点:异步操作完成后,状态机可能已经被其他操作改变,必须验证当前状态。
c#private void OnStateChanged(object sender, StateTransitionEventArgs e)
{
// 关键:立即更新按钮状态
UpdateButtonStates();
// 防止并发问题
if (InvokeRequired)
{
Invoke(new Action(() => UpdateUI()));
}
else
{
UpdateUI();
}
}
防坑提醒:状态变化后必须立即更新UI,否则用户可能点击不应该被允许的按钮。
c#public enum OrderState
{
Created, Paid, Processing, Shipped, Delivered, Cancelled, Returned
}
// 配置订单状态流转
_machine.Configure(OrderState.Created)
.Permit(OrderEvent.Pay, OrderState.Paid)
.Permit(OrderEvent.Cancel, OrderState.Cancelled)
.PermitIf(OrderEvent.AutoCancel, OrderState.Cancelled, () => IsExpired());
c#public enum PlayerState { Idle, Moving, Attacking, Casting, Dead }
_machine.Configure(PlayerState.Idle)
.Permit(PlayerAction.Move, PlayerState.Moving)
.PermitIf(PlayerAction.Attack, PlayerState.Attacking, () => HasTarget())
.PermitIf(PlayerAction.Cast, PlayerState.Casting, () => HasMana());
通过这个完整的工业设备状态机实战案例,我们彻底解决了复杂状态管理的难题:
🎯 三个核心收获:
三句金句送给你:
收藏级代码模板:文中的DeviceStateMachine类和UI集成代码可以直接复制到你的项目中使用,只需要根据具体业务调整状态和指令定义即可。这套模板已经包含了异步处理、错误处理、UI同步等生产环境必备的所有特性。
你在项目中遇到过哪些复杂的状态管理场景?是用什么方式解决的?欢迎在评论区分享你的经验,或者说说看了这篇文章后准备如何重构现有代码!
觉得这篇干货有用,请转发给更多需要的C#开发同行!让我们一起告别混乱的if-else,拥抱优雅的状态机! 🚀
关注我,获取更多C#开发实战技巧,让编程变得更简单!
相关信息
通过网盘分享的文件:AppIndustrialStateMachine.zip 链接: https://pan.baidu.com/s/1nHgPtMwj3Ao-UGqCT8FgKg?pwd=9sjp 提取码: 9sjp --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!