C# 关于状态机的实现(案例版)

大部分的状态机都是有限状态机,某些业务环境,或者其他环境中,如果有状态机其实还是很方便的。比如,我是用在了单个客户的Socket通信上,未连接状态,我就等连接。已连接状态,就等待下一步指令状态。这样的,逻辑就会简化许多。

以前在C语言上,自己实现过状态机,但是,过去好久了。也想通过C#实现,看看是不是方便许多。

状态机的实现

状态机接口对象

/// <summary>/// 状态对象/// </summary>public interface IStateObject{/// <summary>/// 进入状态/// </summary>void EnterState();/// <summary>/// 离开状态/// </summary>void ExitState();/// <summary>/// 更新状态/// </summary>void UpdateState();}

也可以在 更新状态里,自己设置下一个状态。算是转到指定状态上。

比如登录成功

状态机核心逻辑

/// <summary>/// 状态机/// </summary>public class StateMachine{/// <summary>/// 运行 Update 时间间隔 毫秒/// </summary>public int RunInterval = 500;/// <summary>/// 当前状态/// </summary>private string CurrentState;/// <summary>/// 字典存放当前所有对象/// </summary>private Dictionary<string, IStateObject> Dic = new();/// <summary>/// 当前的线程对象/// </summary>private Thread thread;/// <summary>/// 是否已经在运行/// </summary>private bool IsRun = false;public StateMachine(int runInterval = 500){this.RunInterval = runInterval;}/// <summary>/// 注册一个状态对象/// </summary>/// <param name="stateObject"></param>/// <param name="istateObject"></param>public void Register(string stateObject, IStateObject istateObject){Dic.TryAdd(stateObject, istateObject);}/// <summary>/// 注册一个状态对象/// </summary>/// <param name="stateObject"></param>/// <param name="istateObject"></param>public void Register(Dictionary<string, IStateObject> stateObjects){if (stateObjects?.Any() == true){foreach (var item in stateObjects){Dic.TryAdd(item.Key, item.Value);}}}/// <summary>/// 设置当前状态/// </summary>/// <param name="stateObject"></param>public void SetState(string stateObject){if (CurrentState != stateObject){if (CurrentState != null && Dic.TryGetValue(CurrentState, out var oldObj)){oldObj.ExitState();}CurrentState = stateObject;if (CurrentState != null && Dic.TryGetValue(CurrentState, out var newObj)){newObj.EnterState();}}}/// <summary>/// 自己启动服务/// </summary>public void Start(){if (!IsRun){IsRun = true;thread = new Thread(new ThreadStart(Run));thread.IsBackground = true;thread.Start();Console.WriteLine("状态机启动");}}/// <summary>/// 自己停止服务/// </summary>public void Close(){if (IsRun){//最后一个状态直接退出if (CurrentState != null && Dic.TryGetValue(CurrentState, out var oldObj)){oldObj.ExitState();}IsRun = false;try{thread.Interrupt();}catch (Exception){}Thread.Sleep(50);thread = null;Console.WriteLine("状态机关闭");}}/// <summary>/// 线程执行的任务/// </summary>private void Run(){try{while (IsRun){Updata();SpinWait.SpinUntil(() => !IsRun, RunInterval);}}catch (Exception) { };}/// <summary>/// 更新数据/// </summary>public void Updata(){if (CurrentState != null && Dic.TryGetValue(CurrentState, out var objobj)){objobj.UpdateState();}}}

这个是状态机的核心实现,大佬随便看一下应该就知道啥意思了。

定义两个状态对象

/// <summary>
/// 一只猫
/// </summary>
public class Cat : IStateObject 
{public void EnterState(){Console.WriteLine("小猫进来了");}public void ExitState(){Console.WriteLine("小猫出去了");}public void UpdateState(){Console.WriteLine("小猫在玩逗猫棒!");}
}
/// <summary>
/// 一只狗
/// </summary>
public class Dog : IStateObject 
{public void EnterState(){Console.WriteLine("小狗进来了");}public void ExitState(){Console.WriteLine("小狗出去了");}public void UpdateState(){Console.WriteLine("小狗在玩耍!");}
}

一只猫,一只狗,就可以切换状态效果了。

测试代码

static void Main(string[] args)
{StateMachine stateMachine = new StateMachine(1500);//状态机//根据当前的不同的状态,做出不同的事件操作stateMachine.Register(nameof(Cat), new Cat());stateMachine.Register(nameof(Dog), new Dog());//启动状态机stateMachine.Start();//开始执行状态机//设置当前状态stateMachine.SetState(nameof(Cat));Thread.Sleep(2000);stateMachine.SetState(nameof(Dog));Thread.Sleep(2000);stateMachine.SetState(nameof(Cat));Thread.Sleep(2000);//状态机停止stateMachine.Close();Console.WriteLine("状态机执行完毕!");Console.ReadLine();
}

运行结果

4dd2dd70d0f8fab3ffacb8a515ceb233.png

总结

状态机C#实现完之后,用着还是挺方便的。对于有些流程也可以用状态机来实现。

代码地址

https://github.com/kesshei/StateMachineDemo.git

https://gitee.com/kesshei/StateMachineDemo.git

一键三连呦!,感谢大佬的支持,您的支持就是我的动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285144.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

测试并发应用 (一)监控Lock接口

声明&#xff1a;本文是《 Java 7 Concurrency Cookbook 》的第八章&#xff0c; 作者&#xff1a; Javier Fernndez Gonzlez 译者&#xff1a;郑玉婷 校对&#xff1a;方腾飞 监控Lock接口 Lock 接口是Java 并发 API提供的最基本的机制来同步代码块。它允许定义临界区。临界…

[There will be more story......]

This blog will keep on updating.转载于:https://www.cnblogs.com/SinGuLaRiTy2001/p/7965776.html

根据生日得到星座

--得到星座 function DataCenter_Setting:GetConstellation(month, day)local dataInfo {121, 220, 321, 421, 522, 622, 723, 824, 924, 1024, 1123, 1222}local Constellations {"水瓶", "双鱼", "白羊", "金牛", "双子"…

[转]Android 项目的代码混淆,Android proguard 使用说明

简介 Java代码是非常容易反编译的。为了很好的保护Java源代码&#xff0c;我们往往会对编译好的class文件进行混淆处理。 ProGuard是一个混淆代码的开源项目。它的主要作用就是混淆&#xff0c;当然它还能对字节码进行缩减体积、优化等&#xff0c;但那些对于我们来说都算是次要…

数据结构与算法:终于可以用三种语言(C,C#,JavaScript)把图的广度优先遍历讲清楚了(推荐收藏)

文章目录邻接矩阵存储图的广度优先遍历过程分析C语言实现队列编程程序中加入图的处理函数结果的再次分析C#语言实现图的广度优先遍历、并显示广度优先遍历生成树JavaScript语言实现图的广度优先遍历、并显示广度优先遍历生成树邻接矩阵存储图的广度优先遍历过程分析 对图1这样…

C语言试题161之求100000以内的自守数

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款刷算法、笔试、面经、拿大公司offer神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:自守数是…

改造.NET遗留应用

浅议.NET遗留应用改造TLDR&#xff1a;本文介绍了遗留应用改造中的一些常见问题&#xff0c;并对改造所能开展的目标、原则、策略进行了概述。一、背景概述1、概述或许仅“遗留应用”这个标题就比较吸睛&#xff0c;因为我听过太多人吐槽了。Robert Martin在《修改代码的艺术》…

GitHub的DGit改进了平台的可靠性、性能以及可用性

GitHub最近悄悄地发布了DGit&#xff0c;全称为“分布式Git”。这是一种基于Git创建的分布式存储系统&#xff0c;其目标是改进使用GitHub时的可靠性、可用性以及性能。\\DGit是一个应用层面的协议&#xff0c;它利用了Git分布式的特性&#xff0c;将每个仓库在三台不同的、独立…

用静态NAT实现外网PC访问内网服务器

在我们的生产环境中常常处于安全考虑将服务器置于内网环境中&#xff0c;但同时得向外网提供各种服务功能&#xff0c;此时就需要用到NAT技术。下面是我用思科的仿真软件搭建的一个实验环境&#xff0c;实现外网PC访问内网服务器。先说明一下实验环境&#xff1a;路由器R0左边为…

[转]分布式事务之TCC服务设计和实现注意事项

1、TCC简介 TCC是一种比较成熟的分布式事务解决方案&#xff0c;可用于解决跨库操作的数据一致性问题&#xff1b; TCC是服务化的两阶段编程模型&#xff0c;其Try、Confirm、Cancel 3个方法均由业务编码实现&#xff1b; 其中Try操作作为一阶段&#xff0c;负责资源的检查和…

量化投资策略的评估标准及其计算公式

收益率指标&#xff1a;分为策略的总收益率和策略的年化收益率 策略的总收益率&#xff1a; 策略的总收益率是评价一个策略盈利能力的最基本的指标&#xff0c;其计算方法为&#xff1a; 公式中Vt表示策略最终的股票和现金的总价值&#xff0c;V0表示策略最初的股票和现金的总…

.net post xml 数据

var request WebRequest.Create(url);//url 是post 接口的URL request.Method "post";// 请求方法 request.ContentType "text/xml"; //请求类型 request.Headers.Add("charset:utf-8"); //设置文档类型的编码格式 var encoding Encoding.Ge…

【ArcGIS微课1000例】0005:空间连接(Spatial Join)

问题描述 现在要根据范围,怎样批量统计各个范围内的湖泊的总面积、各个省份内的铁路或河流总长度、各个地区的人口综合等。 空间连接 根据空间关系将一个要素类的属性连接到另一个要素类的属性。目标要素和来自连接要素的被连接属性写入到输出要素类。 用法 空间连接是指根…

【微服务专题之】.Net6中集成消息队列-RabbitMQ中直接路由模式

微信公众号&#xff1a;趣编程ACE关注可了解更多的.NET日常实战开发技巧&#xff0c;如需源码 请公众号后台留言 源码;[如果觉得本公众号对您有帮助&#xff0c;欢迎关注]前文回顾【微服务专题之】.Net6下集成消息队列上-RabbitMQ【微服务专题之】.Net6下集成消息队列2-RabbitM…

C语言试题162之圆周率π

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款刷算法、笔试、面经、拿大公司offer神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:圆周率π…

第14、15教学周作业

要求一 还差一些没做完。 要求二 USTH_C程序设计&#xff08;基础&#xff09;14周第一次PTA作业 7-3 将数组中的数逆序存放 1.实验代码 #include<stdio.h>int main() {int i,n,t;scanf("%d",&n);int a[n];for(i0;i<n;i){scanf("%d",&t)…

篇三:访问JSON静态文件

背景&#xff1a;在定位的时候带出车牌号的前两位&#xff0c;这里就有一个地址和车牌号前两位的映射关系&#xff0c;这个映射关系起初是通过Ajax在页面加载的时候请求去数据库里面查出来赋给一个变量&#xff0c;然后去操作&#xff0c;但是这个过程通常需要4~7秒&#xff0c…

代理(Proxy)

2019独角兽企业重金招聘Python工程师标准>>> 一、代理的概念 动态代理技术是整个java技术中最重要的一个技术&#xff0c;它是学习java框架的基础&#xff0c;不会动态代理技术&#xff0c;那么在学习Spring这些框架时是学不明白的。 动态代理技术就是用来产生一个对…

【ArcGIS微课1000例】0006:创建随机点(Create Random Points)

问题描述 在一个给定的范围内,根据随机位置,生成指定数量的随机点。生成的随机点通常用来提取每个点对应的NDVI,高程,气温等值。 ArcGIS创建随机点 创建指定数量的随机点要素。可以在范围窗口中、面要素内、点要素上或线要素沿线生成随机点。 工具介绍:

C语言试题163之计算某一天是对应年的第几天,这一年一共多少天;计算两个日期之间相隔的天数。两个日期由键盘输入。

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款刷算法、笔试、面经、拿大公司offer神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:计算某一…