C# 状态机编程实战:工业级应用开发全攻略

96 阅读5分钟

前言

在工业控制、游戏开发及工作流系统等复杂业务场景中,传统代码常因大量if-else判断陷入"维护困难、扩展性差、容易出错"的困境。

本文通过一个完整的WinForm工业设备控制系统案例,系统解析C#状态机编程的核心精髓,帮助开发者掌握结构化设计、安全控制与可视化反馈三大核心能力,实现从"混乱条件判断"到"优雅状态管理"的思维升级。

正文

问题分析:传统代码的痛点

在没有状态机的情况下,业务逻辑常以分散的条件判断形式存在。

例如,设备启动逻辑需嵌套多层if-else判断当前状态是否为"空闲"、是否已初始化等。这种代码存在四大缺陷:

维护困难:业务逻辑散落在多个方法中,修改时需全局搜索关联逻辑;

扩展性差:新增状态需修改多处代码,易引发连锁错误; 容易出错:状态转换逻辑易遗漏或冲突,导致运行时错误;

测试复杂:需覆盖所有状态组合路径,测试成本高昂。

解决方案:状态机模式的核心设计

状态机通过状态转换表将业务逻辑结构化,实现"清晰、可维护、易扩展"的代码设计。

其核心思想如图所示:

代码实战

工业级状态机实现

1、定义状态与事件枚举

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       // 完成
    }
}

状态机核心类

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()
            };
        }
    }
}

2、状态转换规则设计

空闲状态(Idle):允许操作"初始化"或"进入维护",禁止直接启动;

初始化状态(Initializing):异步初始化成功则进入"准备就绪",失败则进入"错误";

运行状态(Running):支持"暂停""停止"或"错误处理",确保运行逻辑可控。

3、工业界面构建效果

系统界面通过状态同步实现可视化反馈,界面截图如下:

实际应用场景拓展

1、工业控制系统

生产线设备"启动→预热→运行→停止→维护"

机械臂"待机→标定→工作→错误处理"

2、游戏开发

角色"站立→移动→跳跃→攻击→死亡"

游戏流程"菜单→游戏中→暂停→结束"

3、工作流系统

订单"创建→审核→生产→发货→完成"

审批"提交→初审→复审→批准→归档"流程。

常见问题与优化技巧

状态转换表设计不完整:需覆盖所有状态-事件组合,避免未定义转换;

并发访问问题:需通过锁机制或线程安全设计防止状态竞争;

日志记录缺失:应记录状态转换历史,便于问题追踪;

性能优化:采用switch表达式替代多层if-else,预编译状态转换表提升效率。

总结

状态机模式通过"结构化设计、安全控制、可视化反馈"三大核心要点,将复杂业务逻辑转化为清晰的状态转换路径。它不仅是一种编程模式,更是一种"将复杂问题分解为清晰状态与转换"的思维方式。

关键词

状态机、C#编程、工业控制系统、游戏开发、工作流系统、状态转换表、结构化设计、安全控制、可视化反馈

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:技术老小子

出处:mp.weixin.qq.com/s/NHDcKflvYX2FPdgd-U9lpQ

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!