编辑
2025-10-13
C#
00

目录

🎯 问题分析:为什么需要状态机?
传统代码的痛点
💡 解决方案:优雅的状态机模式
🔥 核心设计思想
🛠️ 代码实战:构建工业级状态机
第一步:定义状态和事件枚举
第二步:实现状态机核心类
1. 空闲状态 (Idle)
2. 初始化状态 (Initializing)
3. 准备状态 (Ready)
4. 运行状态 (Running)
5. 暂停状态 (Paused)
第三步:构建美观的工业界面
⚡ 实际应用场景
🏭 工业控制系统
🎮 游戏开发
📋 工作流系统
⚠️ 常见坑点提醒
1. 状态转换表设计不完整
2. 忘记处理并发访问
3. 状态转换缺乏日志记录
🚀 性能优化技巧
使用switch表达式优化状态判断
预编译状态转换表
💎 收藏级代码模板
通用状态机基类
📈 扩展建议
🎯 总结与思考

你是否在开发复杂业务流程时遇到过这样的困扰:代码中充斥着大量的if-else判断,业务状态难以维护,流程控制逻辑混乱不堪?特别是在工业控制、游戏开发、工作流系统中,状态管理往往成为项目的技术难点。

**今天,我将通过一个完整的WinForm工业设备控制系统,带你掌握C#状态机编程的精髓。**这不仅是一个编程模式的学习,更是解决复杂业务逻辑的利器。无论你是初学者还是有经验的开发者,这篇文章都会让你对状态机有全新的认识。

🎯 问题分析:为什么需要状态机?

传统代码的痛点

在没有状态机的情况下,我们通常会这样写代码:

C#
// 传统方式:充满条件判断的混乱代码 public void StartMachine() { if (currentStatus == "idle") { if (isInitialized) { currentStatus = "running"; } else { MessageBox.Show("请先初始化设备"); } } else if (currentStatus == "error") { MessageBox.Show("设备故障,无法启动"); } // ... 更多复杂的条件判断 }

这种代码存在以下问题:

  • 维护困难:业务逻辑散落在各个方法中
  • 扩展性差:添加新状态需要修改多处代码
  • 容易出错:状态转换逻辑容易遗漏或冲突
  • 测试复杂:难以覆盖所有状态组合

💡 解决方案:优雅的状态机模式

状态机模式通过状态转换表将复杂的业务逻辑结构化,让代码变得清晰、可维护、易扩展。

🔥 核心设计思想

image.png

🛠️ 代码实战:构建工业级状态机

第一步:定义状态和事件枚举

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppStateMachine { /// <summary> /// 设备状态枚举 /// </summary> public enum MachineState { Idle, // 空闲 Initializing, // 初始化 Ready, // 准备就绪 Running, // 运行中 Paused, // 暂停 Stopping, // 停止中 Error, // 错误 Maintenance // 维护 } /// <summary> /// 状态转换事件枚举 /// </summary> public enum StateEvent { Initialize, // 初始化 Start, // 启动 Pause, // 暂停 Resume, // 恢复 Stop, // 停止 Reset, // 重置 Error, // 错误 Maintain, // 维护 Complete // 完成 } }

第二步:实现状态机核心类

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppStateMachine { /// <summary> /// 状态机核心类 /// </summary> public class StateMachine { private MachineState _currentState; private Dictionary<(MachineState, StateEvent), MachineState> _stateTransitions; public MachineState CurrentState { get => _currentState; private set { var oldState = _currentState; _currentState = value; OnStateChanged?.Invoke(oldState, _currentState); } } public event Action<MachineState, MachineState> OnStateChanged; public event Action<string> OnLogMessage; public StateMachine() { _currentState = MachineState.Idle; InitializeStateTransitions(); } /// <summary> /// 初始化状态转换表 /// </summary> private void InitializeStateTransitions() { _stateTransitions = new Dictionary<(MachineState, StateEvent), MachineState> { // 从空闲状态的转换 { (MachineState.Idle, StateEvent.Initialize), MachineState.Initializing }, { (MachineState.Idle, StateEvent.Maintain), MachineState.Maintenance }, // 从初始化状态的转换 { (MachineState.Initializing, StateEvent.Complete), MachineState.Ready }, { (MachineState.Initializing, StateEvent.Error), MachineState.Error }, // 从准备状态的转换 { (MachineState.Ready, StateEvent.Start), MachineState.Running }, { (MachineState.Ready, StateEvent.Maintain), MachineState.Maintenance }, { (MachineState.Ready, StateEvent.Error), MachineState.Error }, // 从运行状态的转换 { (MachineState.Running, StateEvent.Pause), MachineState.Paused }, { (MachineState.Running, StateEvent.Stop), MachineState.Stopping }, { (MachineState.Running, StateEvent.Error), MachineState.Error }, // 从暂停状态的转换 { (MachineState.Paused, StateEvent.Resume), MachineState.Running }, { (MachineState.Paused, StateEvent.Stop), MachineState.Stopping }, { (MachineState.Paused, StateEvent.Error), MachineState.Error }, // 从停止中状态的转换 { (MachineState.Stopping, StateEvent.Complete), MachineState.Idle }, { (MachineState.Stopping, StateEvent.Error), MachineState.Error }, // 从错误状态的转换 { (MachineState.Error, StateEvent.Reset), MachineState.Idle }, { (MachineState.Error, StateEvent.Maintain), MachineState.Maintenance }, // 从维护状态的转换 { (MachineState.Maintenance, StateEvent.Complete), MachineState.Idle } }; } /// <summary> /// 触发状态转换事件 /// </summary> public bool TriggerEvent(StateEvent stateEvent) { if (_stateTransitions.TryGetValue((CurrentState, stateEvent), out MachineState newState)) { var message = $"状态转换: {GetStateDisplayName(CurrentState)}{GetStateDisplayName(newState)} (事件: {GetEventDisplayName(stateEvent)})"; OnLogMessage?.Invoke(message); CurrentState = newState; return true; } else { var message = $"无效的状态转换: 在状态 {GetStateDisplayName(CurrentState)} 下无法处理事件 {GetEventDisplayName(stateEvent)}"; OnLogMessage?.Invoke(message); return false; } } /// <summary> /// 获取当前状态允许的事件 /// </summary> public List<StateEvent> GetAllowedEvents() { var allowedEvents = new List<StateEvent>(); foreach (var transition in _stateTransitions.Keys) { if (transition.Item1 == CurrentState) { allowedEvents.Add(transition.Item2); } } return allowedEvents; } /// <summary> /// 获取状态显示名称 /// </summary> public static string GetStateDisplayName(MachineState state) { return state switch { MachineState.Idle => "空闲", MachineState.Initializing => "初始化中", MachineState.Ready => "准备就绪", MachineState.Running => "运行中", MachineState.Paused => "已暂停", MachineState.Stopping => "停止中", MachineState.Error => "错误", MachineState.Maintenance => "维护中", _ => state.ToString() }; } /// <summary> /// 获取事件显示名称 /// </summary> public static string GetEventDisplayName(StateEvent stateEvent) { return stateEvent switch { StateEvent.Initialize => "初始化", StateEvent.Start => "启动", StateEvent.Pause => "暂停", StateEvent.Resume => "恢复", StateEvent.Stop => "停止", StateEvent.Reset => "重置", StateEvent.Error => "错误", StateEvent.Maintain => "维护", StateEvent.Complete => "完成", _ => stateEvent.ToString() }; } } }

1. 空闲状态 (Idle)

  • 允许操作:初始化设备 或 进入维护模式
  • 业务含义:设备空闲时,只能进行初始化或维护,不能直接启动

2. 初始化状态 (Initializing)

  • 允许操作:初始化完成 或 出现错误
  • 业务含义:初始化是异步过程,要么成功进入准备状态,要么失败进入错误状态

3. 准备状态 (Ready)

  • 允许操作:启动运行、进入维护、处理错误
  • 业务含义:设备已准备就绪,可以开始正常工作

4. 运行状态 (Running)

  • 允许操作:暂停、停止、处理错误
  • 业务含义:设备正常运行时的控制选项

5. 暂停状态 (Paused)

  • 允许操作:恢复运行、彻底停止、处理错误
  • 业务含义:暂停是可恢复的状态

第三步:构建美观的工业界面

C#
using Timer = System.Windows.Forms.Timer; namespace AppStateMachine { public partial class Form1 : Form { private StateMachine _stateMachine; private Timer _simulationTimer; private Random _random; public Form1() { InitializeComponent(); CreateStateIndicators(); InitializeStateMachine(); InitializeTimer(); _random = new Random(); } private void InitializeStateMachine() { _stateMachine = new StateMachine(); _stateMachine.OnStateChanged += OnStateChanged; _stateMachine.OnLogMessage += OnLogMessage; UpdateUI(); } private void CreateStateIndicators() { var states = new[] { (MachineState.Idle, "空闲"), (MachineState.Initializing, "初始化"), (MachineState.Ready, "准备"), (MachineState.Running, "运行"), (MachineState.Paused, "暂停"), (MachineState.Stopping, "停止"), (MachineState.Error, "错误"), (MachineState.Maintenance, "维护") }; int x = 5, y = 5; foreach (var (state, displayName) in states) { var indicator = new System.Windows.Forms.Label { Size = new System.Drawing.Size(50, 25), Location = new System.Drawing.Point(x, y), Text = displayName, TextAlign = System.Drawing.ContentAlignment.MiddleCenter, BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle, BackColor = System.Drawing.Color.LightGray, Font = new System.Drawing.Font("Microsoft Sans Serif", 8F), Tag = state.ToString() }; panelStateIndicators.Controls.Add(indicator); x += 55; if (x > 400) { x = 5; y += 30; } } } private void InitializeTimer() { _simulationTimer = new Timer(); _simulationTimer.Interval = 2000; // 2秒 _simulationTimer.Tick += SimulationTimer_Tick; } private void OnStateChanged(MachineState oldState, MachineState newState) { if (InvokeRequired) { Invoke(new Action<MachineState, MachineState>(OnStateChanged), oldState, newState); return; } UpdateUI(); // 自动处理某些状态 switch (newState) { case MachineState.Initializing: _simulationTimer.Start(); // 模拟初始化过程 break; case MachineState.Stopping: _simulationTimer.Start(); // 模拟停止过程 break; default: _simulationTimer.Stop(); break; } } private void SimulationTimer_Tick(object sender, EventArgs e) { // 模拟异步操作完成 if (_stateMachine.CurrentState == MachineState.Initializing || _stateMachine.CurrentState == MachineState.Stopping) { _stateMachine.TriggerEvent(StateEvent.Complete); } } private void OnLogMessage(string message) { if (InvokeRequired) { Invoke(new Action<string>(OnLogMessage), message); return; } var timestamp = DateTime.Now.ToString("HH:mm:ss"); listBoxLog.Items.Insert(0, $"[{timestamp}] {message}"); if (listBoxLog.Items.Count > 100) { listBoxLog.Items.RemoveAt(100); } } private void UpdateUI() { // 更新状态显示 labelCurrentState.Text = StateMachine.GetStateDisplayName(_stateMachine.CurrentState); labelCurrentState.ForeColor = GetStateColor(_stateMachine.CurrentState); // 更新按钮状态 var allowedEvents = _stateMachine.GetAllowedEvents(); btnInitialize.Enabled = allowedEvents.Contains(StateEvent.Initialize); btnStart.Enabled = allowedEvents.Contains(StateEvent.Start); btnPause.Enabled = allowedEvents.Contains(StateEvent.Pause); btnResume.Enabled = allowedEvents.Contains(StateEvent.Resume); btnStop.Enabled = allowedEvents.Contains(StateEvent.Stop); btnReset.Enabled = allowedEvents.Contains(StateEvent.Reset); btnMaintenance.Enabled = allowedEvents.Contains(StateEvent.Maintain); btnError.Enabled = allowedEvents.Contains(StateEvent.Error); // 更新状态指示器 UpdateStateIndicators(); } private Color GetStateColor(MachineState state) { return state switch { MachineState.Idle => Color.Gray, MachineState.Initializing => Color.Orange, MachineState.Ready => Color.Blue, MachineState.Running => Color.Green, MachineState.Paused => Color.Gold, MachineState.Stopping => Color.Orange, MachineState.Error => Color.Red, MachineState.Maintenance => Color.Purple, _ => Color.Black }; } private void UpdateStateIndicators() { // 重置所有指示器 foreach (Control control in panelStateIndicators.Controls) { if (control is Label label) { label.BackColor = Color.LightGray; } } // 点亮当前状态指示器 var currentIndicator = panelStateIndicators.Controls .OfType<Label>() .FirstOrDefault(l => l.Tag?.ToString() == _stateMachine.CurrentState.ToString()); if (currentIndicator != null) { currentIndicator.BackColor = GetStateColor(_stateMachine.CurrentState); } } // 事件处理方法 private void BtnInitialize_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Initialize); private void BtnStart_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Start); private void BtnPause_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Pause); private void BtnResume_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Resume); private void BtnStop_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Stop); private void BtnReset_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Reset); private void BtnMaintenance_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Maintain); private void BtnError_Click(object sender, EventArgs e) => _stateMachine.TriggerEvent(StateEvent.Error); private void BtnClearLog_Click(object sender, EventArgs e) { listBoxLog.Items.Clear(); } } }

image.png

image.png

image.png

⚡ 实际应用场景

🏭 工业控制系统

  • 生产线设备:启动→预热→运行→停止→维护
  • 机械臂控制:待机→标定→工作→错误处理

🎮 游戏开发

  • 角色状态:站立→移动→跳跃→攻击→死亡
  • 游戏流程:菜单→游戏中→暂停→结束

📋 工作流系统

  • 订单处理:创建→审核→生产→发货→完成
  • 审批流程:提交→初审→复审→批准→归档

⚠️ 常见坑点提醒

1. 状态转换表设计不完整

C#
// ❌ 错误:遗漏错误状态的处理 { (MachineState.Running, StateEvent.Start), MachineState.Running } // ✅ 正确:考虑所有可能的异常情况 { (MachineState.Running, StateEvent.Error), MachineState.Error }

2. 忘记处理并发访问

C#
// ✅ 线程安全的状态更新 private readonly object _lockObject = new object(); public bool TriggerEvent(StateEvent stateEvent) { lock (_lockObject) { // 状态转换逻辑 } }

3. 状态转换缺乏日志记录

C#
// ✅ 完善的日志记录,便于调试和监控 OnLogMessage?.Invoke($"[{DateTime.Now:HH:mm:ss}] 状态转换: {oldState}{newState} (触发: {stateEvent})");

🚀 性能优化技巧

使用switch表达式优化状态判断

C#
// ✅ C# 8.0+ 推荐写法 public string GetStateDescription(MachineState state) => state switch { MachineState.Idle => "设备空闲,可以开始初始化", MachineState.Running => "设备正常运行中", MachineState.Error => "设备故障,请检查并重置", _ => "未知状态" };

预编译状态转换表

C#
// ✅ 使用静态只读字典提升性能 private static readonly Dictionary<(MachineState, StateEvent), MachineState> StateTransitions = new Dictionary<(MachineState, StateEvent), MachineState> { // 预定义所有转换规则 };

💎 收藏级代码模板

通用状态机基类

C#
/// <summary> /// 🎯 通用状态机基类 - 可复用的状态机框架 /// </summary> public abstract class StateMachineBase<TState, TEvent> where TState : Enum where TEvent : Enum { protected TState _currentState; protected Dictionary<(TState, TEvent), TState> _transitions; public TState CurrentState => _currentState; public event Action<TState, TState> OnStateChanged; protected abstract void InitializeTransitions(); public virtual bool TriggerEvent(TEvent eventType) { if (_transitions.TryGetValue((_currentState, eventType), out var newState)) { var oldState = _currentState; _currentState = newState; OnStateChanged?.Invoke(oldState, newState); return true; } return false; } }

📈 扩展建议

想要进一步提升状态机的功能?可以考虑以下扩展:

  1. 异步状态转换:支持async/await的异步操作
  2. 状态持久化:将状态保存到数据库或文件
  3. 状态机可视化:生成状态转换图
  4. 条件转换:基于业务规则的条件判断

🎯 总结与思考

通过这个完整的工业设备控制系统示例,我们学习了状态机模式的三个核心要点:

  1. 结构化设计:用状态转换表替代复杂的条件判断
  2. 安全控制:只允许合法的状态转换,避免业务逻辑错误
  3. 可视化反馈:通过UI状态同步让用户清楚了解当前系统状态

状态机不仅是一种编程模式,更是一种思维方式。它教会我们如何将复杂问题分解为清晰的状态和转换,让代码更加优雅、可维护。

🤔 互动讨论

  • 你在项目中遇到过哪些适合使用状态机的场景?
  • 对于异步状态转换,你会如何设计和实现?

觉得这篇文章对你的C#开发有帮助?请转发给更多同行,让大家一起提升代码质量!

关注我,持续分享更多C#开发实战经验和最佳实践!

相关信息

通过网盘分享的文件:AppStateMachine.zip 链接: https://pan.baidu.com/s/1Ocx9qQU4_VQUa89OjBaQvQ?pwd=hbqa 提取码: hbqa --来自百度网盘超级会员v9的分享

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!