你是否在开发复杂业务流程时遇到过这样的困扰:代码中充斥着大量的if-else判断,业务状态难以维护,流程控制逻辑混乱不堪?特别是在工业控制、游戏开发、工作流系统中,状态管理往往成为项目的技术难点。
**今天,我将通过一个完整的WinForm工业设备控制系统,带你掌握C#状态机编程的精髓。**这不仅是一个编程模式的学习,更是解决复杂业务逻辑的利器。无论你是初学者还是有经验的开发者,这篇文章都会让你对状态机有全新的认识。
在没有状态机的情况下,我们通常会这样写代码:
C#// 传统方式:充满条件判断的混乱代码
public void StartMachine()
{
if (currentStatus == "idle")
{
if (isInitialized)
{
currentStatus = "running";
}
else
{
MessageBox.Show("请先初始化设备");
}
}
else if (currentStatus == "error")
{
MessageBox.Show("设备故障,无法启动");
}
// ... 更多复杂的条件判断
}
这种代码存在以下问题:
状态机模式通过状态转换表将复杂的业务逻辑结构化,让代码变得清晰、可维护、易扩展。
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()
};
}
}
}
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();
}
}
}
C#// ❌ 错误:遗漏错误状态的处理
{ (MachineState.Running, StateEvent.Start), MachineState.Running }
// ✅ 正确:考虑所有可能的异常情况
{ (MachineState.Running, StateEvent.Error), MachineState.Error }
C#// ✅ 线程安全的状态更新
private readonly object _lockObject = new object();
public bool TriggerEvent(StateEvent stateEvent)
{
lock (_lockObject)
{
// 状态转换逻辑
}
}
C#// ✅ 完善的日志记录,便于调试和监控
OnLogMessage?.Invoke($"[{DateTime.Now:HH:mm:ss}] 状态转换: {oldState} → {newState} (触发: {stateEvent})");
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;
}
}
想要进一步提升状态机的功能?可以考虑以下扩展:
通过这个完整的工业设备控制系统示例,我们学习了状态机模式的三个核心要点:
状态机不仅是一种编程模式,更是一种思维方式。它教会我们如何将复杂问题分解为清晰的状态和转换,让代码更加优雅、可维护。
🤔 互动讨论:
觉得这篇文章对你的C#开发有帮助?请转发给更多同行,让大家一起提升代码质量!
关注我,持续分享更多C#开发实战经验和最佳实践!
相关信息
通过网盘分享的文件:AppStateMachine.zip 链接: https://pan.baidu.com/s/1Ocx9qQU4_VQUa89OjBaQvQ?pwd=hbqa 提取码: hbqa --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!