news 2026/5/19 23:04:52

C#状态机

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#状态机

一、状态机的核心概念

1. 什么是状态机?

状态机(Finite State Machine, FSM,又称有限状态机)是一种数学模型和编程思想,用于描述一个对象(或系统)在其生命周期内的有限个状态,以及这些状态之间的转移规则、触发转移的事件 / 条件,还有状态转移过程中(或处于某个状态时)需要执行的动作 / 行为

简单理解:它就像对象的 “行为剧本”,规定了对象在什么状态下,遇到什么事情,应该切换到什么新状态,同时要做什么事。

2. 状态机的核心组成要素

一个完整的有限状态机包含 4 个核心部分,缺一不可:

  • 状态(State):对象的离散状态,数量有限。例如 “电梯停止”“电梯上行”“电梯下行”;“订单待支付”“订单已支付”“订单已取消”。
  • 事件(Event/Trigger):触发状态转移的外部或内部条件 / 信号。例如 “乘客按下 5 楼按钮”(触发电梯上行)、“用户完成支付”(触发订单从待支付→已支付)。
  • 转移(Transition):从一个状态切换到另一个状态的规则,通常是 “当前状态 + 事件→目标状态”。例如 “电梯停止(当前状态)+ 按下 5 楼按钮(事件)→ 电梯上行(目标状态)”。
  • 动作(Action):在状态转移过程中(或进入 / 退出某个状态时)执行的逻辑。例如 “电梯切换到上行状态时,启动电机并播报‘前往 5 楼’”、“订单变为已支付时,生成物流单号并发送通知”。

3. 状态机的核心价值(解决什么问题)

在编程中,状态机主要解决复杂状态切换的逻辑混乱问题,具体价值体现在:

  • 消除大量嵌套if/elseswitch/case,让状态相关逻辑更清晰、更易维护;
  • 明确状态转移规则,减少 “非法状态” 出现的概率(例如订单已取消后,无法再触发支付);
  • 状态与行为解耦,便于扩展新状态和新转移规则(符合开闭原则);
  • 逻辑可追溯性强,每个状态的行为和转移都有明确定义,便于调试。

二、C# 中状态机的两种实现方式

下面以电商订单状态流转为场景(最经典的状态机应用场景之一),讲解两种常用实现方式。

场景定义(统一约束)

先明确订单的核心状态、事件和转移规则:

核心状态(State)触发事件(Event)目标状态执行动作(Action)
待支付(Pending)用户支付成功已支付(Paid)生成物流单号、发送支付成功通知
待支付(Pending)用户取消订单已取消(Cancelled)释放库存、发送取消通知
已支付(Paid)商家发货已发货(Shipped)更新物流信息、发送发货通知
已发货(Shipped)用户确认收货已完成(Completed)完成订单结算、关闭交易

前置准备:定义枚举(状态和事件)

首先用 C# 枚举明确订单的状态和触发事件,提高代码可读性和类型安全性:

using System; using System.Collections.Generic; // 订单状态枚举 public enum OrderState { Pending, // 待支付 Paid, // 已支付 Shipped, // 已发货 Completed, // 已完成 Cancelled // 已取消 } // 订单事件枚举(触发状态转移的信号) public enum OrderEvent { PaySuccess, // 支付成功 CancelOrder, // 取消订单 ShipGoods, // 商家发货 ConfirmReceipt // 用户确认收货 }

方式 1:简单状态机(基于Dictionary+ 委托,适合简单场景)

这种方式无需复杂的类结构,通过字典存储 “当前状态 + 事件→转移规则”,配合委托封装动作,实现轻量级状态机。

/// <summary> /// 简单订单状态机(基于Dictionary+委托) /// </summary> public class SimpleOrderStateMachine { // 当前订单状态 public OrderState CurrentState { get; private set; } // 订单编号(附加信息) public string OrderId { get; } // 定义转移规则的委托:参数(事件),返回值(是否转移成功) private delegate bool StateTransitionDelegate(OrderEvent @event); // 存储所有状态的转移逻辑:Key=当前状态,Value=该状态对应的转移委托 private readonly Dictionary<OrderState, StateTransitionDelegate> _stateTransitions; /// <summary> /// 构造函数:初始化订单状态机 /// </summary> /// <param name="orderId">订单编号</param> public SimpleOrderStateMachine(string orderId) { OrderId = orderId; CurrentState = OrderState.Pending; // 初始状态为待支付 // 初始化状态转移规则 _stateTransitions = new Dictionary<OrderState, StateTransitionDelegate>() { { OrderState.Pending, HandlePendingState }, { OrderState.Paid, HandlePaidState }, { OrderState.Shipped, HandleShippedState }, { OrderState.Completed, HandleCompletedState }, { OrderState.Cancelled, HandleCancelledState } }; } /// <summary> /// 触发事件,驱动状态机转移 /// </summary> /// <param name="event">触发事件</param> /// <returns>转移是否成功</returns> public bool TriggerEvent(OrderEvent @event) { if (_stateTransitions.TryGetValue(CurrentState, out var transitionDelegate)) { return transitionDelegate(@event); } Console.WriteLine($"【订单{OrderId}】未知状态{CurrentState},无法处理事件{@event}"); return false; } #region 各状态的转移逻辑处理(核心:状态+事件→转移+动作) /// <summary> /// 处理“待支付”状态的转移逻辑 /// </summary> private bool HandlePendingState(OrderEvent @event) { switch (@event) { case OrderEvent.PaySuccess: // 执行状态转移前/后的动作 Console.WriteLine($"【订单{OrderId}】开始处理支付成功逻辑..."); GenerateLogisticsNo(); // 生成物流单号 SendNotification("支付成功,订单已确认"); // 发送通知 // 更新当前状态 CurrentState = OrderState.Paid; Console.WriteLine($"【订单{OrderId}】状态已从{OrderState.Pending}→{OrderState.Paid}"); return true; case OrderEvent.CancelOrder: Console.WriteLine($"【订单{OrderId}】开始处理取消订单逻辑..."); ReleaseStock(); // 释放库存 SendNotification("订单已取消,库存已释放"); CurrentState = OrderState.Cancelled; Console.WriteLine($"【订单{OrderId}】状态已从{OrderState.Pending}→{OrderState.Cancelled}"); return true; default: Console.WriteLine($"【订单{OrderId}】待支付状态无法处理事件{@event}"); return false; } } /// <summary> /// 处理“已支付”状态的转移逻辑 /// </summary> private bool HandlePaidState(OrderEvent @event) { if (@event == OrderEvent.ShipGoods) { Console.WriteLine($"【订单{OrderId}】开始处理商家发货逻辑..."); UpdateLogisticsInfo("顺丰速运:SF1234567890"); SendNotification("商家已发货,请注意查收"); CurrentState = OrderState.Shipped; Console.WriteLine($"【订单{OrderId}】状态已从{OrderState.Paid}→{OrderState.Shipped}"); return true; } Console.WriteLine($"【订单{OrderId}】已支付状态无法处理事件{@event}"); return false; } /// <summary> /// 处理“已发货”状态的转移逻辑 /// </summary> private bool HandleShippedState(OrderEvent @event) { if (@event == OrderEvent.ConfirmReceipt) { Console.WriteLine($"【订单{OrderId}】开始处理确认收货逻辑..."); CompleteOrderSettlement(); SendNotification("订单已完成,感谢您的购买"); CurrentState = OrderState.Completed; Console.WriteLine($"【订单{OrderId}】状态已从{OrderState.Shipped}→{OrderState.Completed}"); return true; } Console.WriteLine($"【订单{OrderId}】已发货状态无法处理事件{@event}"); return false; } /// <summary> /// 处理“已完成”状态的转移逻辑(终态,无后续转移) /// </summary> private bool HandleCompletedState(OrderEvent @event) { Console.WriteLine($"【订单{OrderId}】订单已完成,无法处理任何事件{@event}"); return false; } /// <summary> /// 处理“已取消”状态的转移逻辑(终态,无后续转移) /// </summary> private bool HandleCancelledState(OrderEvent @event) { Console.WriteLine($"【订单{OrderId}】订单已取消,无法处理任何事件{@event}"); return false; } #endregion #region 订单相关动作(业务逻辑) private void GenerateLogisticsNo() { Console.WriteLine($"【订单{OrderId}】生成物流单号:LOG{Guid.NewGuid():N.Substring(0, 10)}"); } private void SendNotification(string message) { Console.WriteLine($"【订单{OrderId}】发送通知:{message}"); } private void ReleaseStock() { Console.WriteLine($"【订单{OrderId}】释放商品库存成功"); } private void UpdateLogisticsInfo(string logisticsInfo) { Console.WriteLine($"【订单{OrderId}】更新物流信息:{logisticsInfo}"); } private void CompleteOrderSettlement() { Console.WriteLine($"【订单{OrderId}】完成订单结算,交易关闭"); } #endregion }

测试代码(使用状态机)

class Program { static void Main(string[] args) { // 1. 创建简单订单状态机实例 var orderStateMachine = new SimpleOrderStateMachine("ORDER_20260112_001"); // 2. 按业务流程触发事件,驱动状态转移 Console.WriteLine("===== 第一步:用户支付订单 ====="); orderStateMachine.TriggerEvent(OrderEvent.PaySuccess); Console.WriteLine("\n===== 第二步:商家发货 ====="); orderStateMachine.TriggerEvent(OrderEvent.ShipGoods); Console.WriteLine("\n===== 第三步:用户确认收货 ====="); orderStateMachine.TriggerEvent(OrderEvent.ConfirmReceipt); Console.WriteLine("\n===== 第四步:尝试在已完成状态下取消订单(非法操作) ====="); orderStateMachine.TriggerEvent(OrderEvent.CancelOrder); Console.ReadKey(); } }

运行结果

===== 第一步:用户支付订单 ===== 【订单ORDER_20260112_001】开始处理支付成功逻辑... 【订单ORDER_20260112_001】生成物流单号:LOGa1b2c3d4e5 【订单ORDER_20260112_001】发送通知:支付成功,订单已确认 【订单ORDER_20260112_001】状态已从Pending→Paid ===== 第二步:商家发货 ===== 【订单ORDER_20260112_001】开始处理商家发货逻辑... 【订单ORDER_20260112_001】更新物流信息:顺丰速运:SF1234567890 【订单ORDER_20260112_001】发送通知:商家已发货,请注意查收 【订单ORDER_20260112_001】状态已从Paid→Shipped ===== 第三步:用户确认收货 ===== 【订单ORDER_20260112_001】开始处理确认收货逻辑... 【订单ORDER_20260112_001】完成订单结算,交易关闭 【订单ORDER_20260112_001】发送通知:订单已完成,感谢您的购买 【订单ORDER_20260112_001】状态已从Shipped→Completed ===== 第四步:尝试在已完成状态下取消订单(非法操作) ===== 【订单ORDER_20260112_001】订单已完成,无法处理任何事件CancelOrder

方式 2:面向对象状态机(基于状态模式,适合复杂场景)

这种方式是状态模式(State Pattern)的典型应用,将每个状态封装为独立的类,状态的转移逻辑和动作都内聚在对应状态类中,符合 “单一职责原则”,扩展性更强(新增状态只需新增一个状态类,无需修改原有代码)。

步骤 1:定义状态接口(统一所有状态的行为)

/// <summary> /// 订单状态接口(统一所有订单状态的行为) /// </summary> public interface IOrderState { /// <summary> /// 处理当前状态下的事件,驱动状态转移 /// </summary> /// <param name="orderContext">订单上下文(持有状态机的核心信息)</param> /// <param name="event">触发事件</param> void Handle(OrderContext orderContext, OrderEvent @event); }

步骤 2:定义订单上下文(封装状态机的公共信息和状态切换)

/// <summary> /// 订单上下文(状态机的载体,持有当前状态和公共信息) /// </summary> public class OrderContext { // 当前订单状态(面向接口编程) public IOrderState CurrentState { get; set; } // 订单编号 public string OrderId { get; } // 构造函数:初始化上下文 public OrderContext(string orderId) { OrderId = orderId; // 初始状态为待支付 CurrentState = new PendingState(); } /// <summary> /// 触发事件,委托给当前状态处理 /// </summary> /// <param name="event">触发事件</param> public void TriggerEvent(OrderEvent @event) { CurrentState.Handle(this, @event); } #region 订单公共动作(供各状态类调用) public void GenerateLogisticsNo() { Console.WriteLine($"【订单{OrderId}】生成物流单号:LOG{Guid.NewGuid():N.Substring(0, 10)}"); } public void SendNotification(string message) { Console.WriteLine($"【订单{OrderId}】发送通知:{message}"); } public void ReleaseStock() { Console.WriteLine($"【订单{OrderId}】释放商品库存成功"); } public void UpdateLogisticsInfo(string logisticsInfo) { Console.WriteLine($"【订单{OrderId}】更新物流信息:{logisticsInfo}"); } public void CompleteOrderSettlement() { Console.WriteLine($"【订单{OrderId}】完成订单结算,交易关闭"); } #endregion }

步骤 3:实现各个具体状态类(内聚对应状态的逻辑)

#region 具体状态类 /// <summary> /// 待支付状态 /// </summary> public class PendingState : IOrderState { public void Handle(OrderContext orderContext, OrderEvent @event) { switch (@event) { case OrderEvent.PaySuccess: Console.WriteLine($"【订单{orderContext.OrderId}】开始处理支付成功逻辑..."); orderContext.GenerateLogisticsNo(); orderContext.SendNotification("支付成功,订单已确认"); // 切换到已支付状态 orderContext.CurrentState = new PaidState(); Console.WriteLine($"【订单{orderContext.OrderId}】状态已从待支付→已支付"); break; case OrderEvent.CancelOrder: Console.WriteLine($"【订单{orderContext.OrderId}】开始处理取消订单逻辑..."); orderContext.ReleaseStock(); orderContext.SendNotification("订单已取消,库存已释放"); // 切换到已取消状态 orderContext.CurrentState = new CancelledState(); Console.WriteLine($"【订单{orderContext.OrderId}】状态已从待支付→已取消"); break; default: Console.WriteLine($"【订单{orderContext.OrderId}】待支付状态无法处理事件{@event}"); break; } } } /// <summary> /// 已支付状态 /// </summary> public class PaidState : IOrderState { public void Handle(OrderContext orderContext, OrderEvent @event) { if (@event == OrderEvent.ShipGoods) { Console.WriteLine($"【订单{orderContext.OrderId}】开始处理商家发货逻辑..."); orderContext.UpdateLogisticsInfo("顺丰速运:SF1234567890"); orderContext.SendNotification("商家已发货,请注意查收"); orderContext.CurrentState = new ShippedState(); Console.WriteLine($"【订单{orderContext.OrderId}】状态已从已支付→已发货"); return; } Console.WriteLine($"【订单{orderContext.OrderId}】已支付状态无法处理事件{@event}"); } } /// <summary> /// 已发货状态 /// </summary> public class ShippedState : IOrderState { public void Handle(OrderContext orderContext, OrderEvent @event) { if (@event == OrderEvent.ConfirmReceipt) { Console.WriteLine($"【订单{orderContext.OrderId}】开始处理确认收货逻辑..."); orderContext.CompleteOrderSettlement(); orderContext.SendNotification("订单已完成,感谢您的购买"); orderContext.CurrentState = new CompletedState(); Console.WriteLine($"【订单{orderContext.OrderId}】状态已从已发货→已完成"); return; } Console.WriteLine($"【订单{orderContext.OrderId}】已发货状态无法处理事件{@event}"); } } /// <summary> /// 已完成状态(终态) /// </summary> public class CompletedState : IOrderState { public void Handle(OrderContext orderContext, OrderEvent @event) { Console.WriteLine($"【订单{orderContext.OrderId}】订单已完成,无法处理任何事件{@event}"); } } /// <summary> /// 已取消状态(终态) /// </summary> public class CancelledState : IOrderState { public void Handle(OrderContext orderContext, OrderEvent @event) { Console.WriteLine($"【订单{orderContext.OrderId}】订单已取消,无法处理任何事件{@event}"); } } #endregion

步骤 4:测试面向对象状态机

class Program { static void Main(string[] args) { // 1. 创建订单上下文(状态机载体) var orderContext = new OrderContext("ORDER_20260112_002"); // 2. 触发事件,驱动状态转移 Console.WriteLine("===== 第一步:用户支付订单 ====="); orderContext.TriggerEvent(OrderEvent.PaySuccess); Console.WriteLine("\n===== 第二步:商家发货 ====="); orderContext.TriggerEvent(OrderEvent.ShipGoods); Console.WriteLine("\n===== 第三步:用户确认收货 ====="); orderContext.TriggerEvent(OrderEvent.ConfirmReceipt); Console.WriteLine("\n===== 第四步:尝试在已完成状态下取消订单(非法操作) ====="); orderContext.TriggerEvent(OrderEvent.CancelOrder); Console.ReadKey(); } }

运行结果(与简单状态机一致,扩展性更强)

===== 第一步:用户支付订单 ===== 【订单ORDER_20260112_002】开始处理支付成功逻辑... 【订单ORDER_20260112_002】生成物流单号:LOGf6g7h8i9j0 【订单ORDER_20260112_002】发送通知:支付成功,订单已确认 【订单ORDER_20260112_002】状态已从待支付→已支付 ===== 第二步:商家发货 ===== 【订单ORDER_20260112_002】开始处理商家发货逻辑... 【订单ORDER_20260112_002】更新物流信息:顺丰速运:SF1234567890 【订单ORDER_20260112_002】发送通知:商家已发货,请注意查收 【订单ORDER_20260112_002】状态已从已支付→已发货 ===== 第三步:用户确认收货 ===== 【订单ORDER_20260112_002】开始处理确认收货逻辑... 【订单ORDER_20260112_002】完成订单结算,交易关闭 【订单ORDER_20260112_002】发送通知:订单已完成,感谢您的购买 【订单ORDER_20260112_002】状态已从已发货→已完成 ===== 第四步:尝试在已完成状态下取消订单(非法操作) ===== 【订单ORDER_20260112_002】订单已完成,无法处理任何事件CancelOrder

三、两种实现方式的对比与适用场景

实现方式优点缺点适用场景
简单状态机(Dictionary + 委托)实现简单、轻量级、无需额外类结构、开发效率高扩展性差(新增状态需修改字典配置和转移逻辑)、复杂场景下逻辑易混乱状态数量少(5 个以内)、转移规则简单、无需频繁扩展的场景
面向对象状态机(状态模式)扩展性强(新增状态只需新增类)、逻辑内聚、可读性高、符合开闭原则实现复杂、类数量多、有一定学习成本状态数量多、转移规则复杂、需要频繁扩展(新增状态 / 事件)的企业级场景(如电商、物流、工作流)

四、C# 中的高级状态机

对于超复杂的状态机场景(如带状态历史、并发状态、子状态机),无需重复造轮子,可以使用成熟的第三方库:

  • Stateless:轻量级、开源的.NET 状态机库,支持流畅 API、委托、异步动作、状态持久化等,NuGet 安装:Install-Package Stateless
  • Automatonymous:基于 MassTransit 的事件驱动状态机库,支持复杂的异步流转和分布式场景,NuGet 安装:Install-Package Automatonymous

总结

  1. 状态机是描述对象有限状态、转移规则、事件和动作的模型,核心价值是解决复杂状态切换的逻辑混乱;
  2. 状态机的 4 个核心要素:状态(State)、事件(Event)、转移(Transition)、动作(Action);
  3. C# 中简单场景可使用Dictionary+委托实现轻量级状态机,复杂场景推荐基于状态模式的面向对象实现;
  4. 状态机的核心思想是 “状态驱动行为”,通过明确的转移规则减少非法状态,提高代码的可维护性和扩展性。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/15 7:17:37

从漏洞频发到固若金汤,C语言裸机程序安全升级的7步实战路径

第一章&#xff1a;从漏洞频发到固若金汤——C语言裸机程序安全演进之路早期的C语言裸机程序因直接操作硬件、缺乏运行时保护机制&#xff0c;常成为安全漏洞的温床。缓冲区溢出、空指针解引用和未初始化内存访问等问题频繁引发系统崩溃或被恶意利用。随着嵌入式系统在工业控制…

作者头像 李华
网站建设 2026/5/12 12:03:29

PCL2-CE社区增强版:打造你的专属Minecraft启动中心

PCL2-CE社区增强版&#xff1a;打造你的专属Minecraft启动中心 【免费下载链接】PCL2-CE PCL2 社区版&#xff0c;可体验上游暂未合并的功能 项目地址: https://gitcode.com/gh_mirrors/pc/PCL2-CE 还在为复杂的Minecraft启动配置而烦恼&#xff1f;PCL2-CE社区增强版为…

作者头像 李华
网站建设 2026/5/11 0:49:34

如何快速掌握ncmdump工具:NCM文件解密转换的终极指南

如何快速掌握ncmdump工具&#xff1a;NCM文件解密转换的终极指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump ncmdump作为网易云音乐NCM格式文件的专业解密工具&#xff0c;通过逆向工程分析实现了对加密音频数据的精准提取&…

作者头像 李华
网站建设 2026/5/17 10:27:36

电商场景实战:用Qwen3-VL-2B快速搭建智能商品描述系统

电商场景实战&#xff1a;用Qwen3-VL-2B快速搭建智能商品描述系统 随着电商平台商品数量的爆炸式增长&#xff0c;传统人工撰写商品描述的方式已难以满足效率与一致性的双重需求。如何利用AI技术自动生成高质量、符合品牌调性的商品文案&#xff0c;成为提升运营效率的关键突破…

作者头像 李华
网站建设 2026/5/19 7:34:51

AI隐私卫士部署规模:从单机到集群的扩展指南

AI隐私卫士部署规模&#xff1a;从单机到集群的扩展指南 1. 背景与需求演进 随着AI技术在图像处理领域的广泛应用&#xff0c;个人隐私保护问题日益受到关注。尤其是在社交媒体、安防监控、医疗影像等场景中&#xff0c;人脸信息的泄露风险显著上升。传统的手动打码方式效率低…

作者头像 李华