C#狀態機編程:工業級應用開發實戰指南
你是否在開發復雜業務流程時遇到過這樣的困擾:代碼中充斥著大量的if-else判斷,業務狀態難以維護,流程控制邏輯混亂不堪?特別是在工業控制、游戲開發、工作流系統中,狀態管理往往成為項目的技術難點。
今天,我將通過一個完整的WinForm工業設備控制系統,帶你掌握C#狀態機編程的精髓。這不僅是一個編程模式的學習,更是解決復雜業務邏輯的利器。無論你是初學者還是有經驗的開發者,這篇文章都會讓你對狀態機有全新的認識。
問題分析:為什么需要狀態機?
傳統代碼的痛點
在沒有狀態機的情況下,我們通常會這樣寫代碼:
// 傳統方式:充滿條件判斷的混亂代碼
public void StartMachine()
{
if (currentStatus == "idle")
{
if (isInitialized)
{
currentStatus = "running";
}
else
{
MessageBox.Show("請先初始化設備");
}
}
elseif (currentStatus == "error")
{
MessageBox.Show("設備故障,無法啟動");
}
// ... 更多復雜的條件判斷
}這種代碼存在以下問題:
- 維護困難業務邏輯散落在各個方法中
- 擴展性差添加新狀態需要修改多處代碼
- 容易出錯狀態轉換邏輯容易遺漏或沖突
- 測試復雜難以覆蓋所有狀態組合
解決方案:優雅的狀態機模式
狀態機模式通過狀態轉換表將復雜的業務邏輯結構化,讓代碼變得清晰、可維護、易擴展。
核心設計思想
圖片
代碼實戰:構建工業級狀態機
第一步:定義狀態和事件枚舉
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppStateMachine
{
/// <summary>
/// 設備狀態枚舉
/// </summary>
publicenum MachineState
{
Idle, // 空閑
Initializing, // 初始化
Ready, // 準備就緒
Running, // 運行中
Paused, // 暫停
Stopping, // 停止中
Error, // 錯誤
Maintenance // 維護
}
/// <summary>
/// 狀態轉換事件枚舉
/// </summary>
publicenum StateEvent
{
Initialize, // 初始化
Start, // 啟動
Pause, // 暫停
Resume, // 恢復
Stop, // 停止
Reset, // 重置
Error, // 錯誤
Maintain, // 維護
Complete // 完成
}
}第二步:實現狀態機核心類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppStateMachine
{
/// <summary>
/// 狀態機核心類
/// </summary>
publicclass StateMachine
{
private MachineState _currentState;
private Dictionary<(MachineState, StateEvent), MachineState> _stateTransitions;
public MachineState CurrentState
{
get => _currentState;
privateset
{
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;
returntrue;
}
else
{
var message = $"無效的狀態轉換: 在狀態 {GetStateDisplayName(CurrentState)} 下無法處理事件 {GetEventDisplayName(stateEvent)}";
OnLogMessage?.Invoke(message);
returnfalse;
}
}
/// <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)
- 允許操作:恢復運行、徹底停止、處理錯誤
- 業務含義:暫停是可恢復的狀態
第三步:構建美觀的工業界面
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();
}
}
}
圖片


實際應用場景
工業控制系統
- 生產線設備:啟動→預熱→運行→停止→維護
- 機械臂控制:待機→標定→工作→錯誤處理
游戲開發
- 角色狀態:站立→移動→跳躍→攻擊→死亡
- 游戲流程:菜單→游戲中→暫停→結束
工作流系統
- 訂單處理:創建→審核→生產→發貨→完成
- 審批流程:提交→初審→復審→批準→歸檔
常見坑點提醒
1. 狀態轉換表設計不完整
// ? 錯誤:遺漏錯誤狀態的處理
{ (MachineState.Running, StateEvent.Start), MachineState.Running }
// ? 正確:考慮所有可能的異常情況
{ (MachineState.Running, StateEvent.Error), MachineState.Error }2. 忘記處理并發訪問
// ? 線程安全的狀態更新
private readonly object _lockObject = new object();
public bool TriggerEvent(StateEvent stateEvent)
{
lock (_lockObject)
{
// 狀態轉換邏輯
}
}3. 狀態轉換缺乏日志記錄
// ? 完善的日志記錄,便于調試和監控
OnLogMessage?.Invoke($"[{DateTime.Now:HH:mm:ss}] 狀態轉換: {oldState} → {newState} (觸發: {stateEvent})");性能優化技巧
使用switch表達式優化狀態判斷
// ? C# 8.0+ 推薦寫法
public string GetStateDescription(MachineState state) => state switch
{
MachineState.Idle => "設備空閑,可以開始初始化",
MachineState.Running => "設備正常運行中",
MachineState.Error => "設備故障,請檢查并重置",
_ => "未知狀態"
};預編譯狀態轉換表
// ? 使用靜態只讀字典提升性能
private static readonly Dictionary<(MachineState, StateEvent), MachineState> StateTransitions =
new Dictionary<(MachineState, StateEvent), MachineState>
{
// 預定義所有轉換規則
};收藏級代碼模板
通用狀態機基類
/// <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);
returntrue;
}
returnfalse;
}
}擴展建議
想要進一步提升狀態機的功能?可以考慮以下擴展:
- 異步狀態轉換支持async/await的異步操作
- 狀態持久化將狀態保存到數據庫或文件
- 狀態機可視化生成狀態轉換圖
- 條件轉換基于業務規則的條件判斷
總結與思考
通過這個完整的工業設備控制系統示例,我們學習了狀態機模式的三個核心要點:
- 結構化設計用狀態轉換表替代復雜的條件判斷
- 安全控制只允許合法的狀態轉換,避免業務邏輯錯誤
- 可視化反饋通過UI狀態同步讓用戶清楚了解當前系統狀態
狀態機不僅是一種編程模式,更是一種思維方式。它教會我們如何將復雜問題分解為清晰的狀態和轉換,讓代碼更加優雅、可維護。
互動討論:
- 你在項目中遇到過哪些適合使用狀態機的場景?
- 對于異步狀態轉換,你會如何設計和實現?























