【C#】C# Winform 热更新 基于ECSharp框架
目录
一、简介
ECSharp (原:EasySharpFrame)
github 地址:https://github.com/suxf/ECSharp
介绍:
1.HTTP服务
2.Websocket服务
3.HyperSocket<自定义Socket服务>
4.TimeFlow<时间流>
5.Sqlserver数据库助手
6.Mysql数据助手
7.Redis数据库助手
8.Log功能
9.热更新功能
10.可变变量
11.事件与命令
不久之前我写过一篇 Winform 自动更新的帖子,虽然很方便,但也有个问题,那就是如果程序运行中出现了错误,那么必须通过服务器更新配置文件和新的文件库,重启客户端,才能更新到最新的版本,如果程序正在运行中,那么是无法动态的去改变原有的逻辑的,所以,这篇文章主要目的就是在程序运行中,做到即时热更。
有人可能会说,这有什么难的,我自己写个 dll,将这个 dll 添加到项目的引用中,运行程序后,把 dll 给替换掉,逻辑不就变了嘛?这个逻辑没毛病,但它也有个问题,程序运行后,这时 dll 已经被占用了,没办法替换了,如下图:
后面,我发现了 ECSharp 这个框架是可以解决文件占用问题,而且在程序运行过程中,随便怎么替换 dll,都不会有文件占用问题,并且还是开源的,可以知道具体是怎么实现的,那么下面就根据官方的资料看看是如何做到热更新的吧。
二、 ECSharp热更新演示
首先,在 Github 上把 ECSharp 源码下载到本地,因为我在项目中,是直接复制官方的源码,或者,你也可以在 NuGet 上安装 EasySharpFrame 插件也是一样的。
新建一个居于 .NET6 框架的控制台项目,取名:HotfixTest,将 ECSharp 部分源码复制过来,添加到项目中,如下图:
在 NuGet 安装 Newtonsoft.Json 插件,不然代码会有错误。
上图中的 Player.cs 是自己新建的,代码如下:
using ECSharp.Hotfix; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HotfixTest { public class Player: AgentData { public string Name { get; set; } = "张三"; public void Say() { Console.WriteLine("我是角色:" + Name); } } public abstract class Dog : AgentData { public string Names = "恶狗"; public int Age = 3; } /// <summary> /// 野狗 /// </summary> public class WildDog : Dog { public int Height = 10; } /// <summary> /// 鬣狗 /// </summary> public class Hyena : Dog { public int Height = 2; } }
Program.cs
using ECSharp.Hotfix; namespace HotfixTest { internal class Program { static void Main(string[] args) { Player player = new Player(); player.Name = "李四"; player.Say(); WildDog dog1 = new WildDog(); Hyena dog2 = new Hyena(); Console.WriteLine("============================="); Console.WriteLine("dog1.Names:" + dog1.Names); Console.WriteLine("dog1.Age:" + dog1.Age); Console.WriteLine("dog1.Height:" + dog1.Height); Console.WriteLine("================="); Console.WriteLine("dog2.Height:" + dog2.Height); Console.WriteLine("============================="); HotfixMgr.Load("Hotfixs", "Hotfixs.Main", new string[] { "参数1", "参数2" }, "Hello"); } } }
HotfixMgr.Load 方法就是用来加载热更的 dll,下面我来解释下这几个参数的意思:
1)Hotfixs --- dll 的文件名,必须保持一致,否则读取不到 dll。
2)Hotfixs.Main --- 要调用的类名,以 “命名空间.类名” 表示。
3)new string[] { "参数1", "参数2" } --- 这里是要调用的方法的参数。
4)Hello --- 方法的名字, 上面的 new string[] { "参数1", "参数2" } 就是给当前方法传递的参数。
下面我们来写热更新的 dll 。
新建一个基于 .NET6 的 类库 项目,取名:Hotfixs,添加一个脚本 Main.cs,把上面的 HotfixTest 生成的 dll 添加到当前项目中,添加 dll 直接用 HotfixTest 项目 Debug 目录中的 HotfixTest.dll 就好了,如下图:
Main.cs
using ECSharp.Hotfix; using HotfixTest; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Hotfixs { public class Main { public static void Hello(string[] args) { Console.WriteLine("============================="); if (args.Length > 0) { for (int i = 0; i < args.Length; i++) { Console.WriteLine(args[i]); } } Console.WriteLine("这是热重载dll,啊哈哈哈哈哈"); Player player1 = AgentDataPivot.AddOrGetObject<Player>("player1"); player1.Say(); player1.Name = "李四他爸"; player1.Say(); Dog dog1 = new WildDog(); Dog dog2 = new Hyena(); Console.WriteLine("============================="); AbsWildDog absWildDog = dog1.GetAbstractAgent<AbsWildDog>(); absWildDog.self.Names = "抽象野狗"; absWildDog.self.Age = 4; absWildDog.Test(); Console.WriteLine("============================="); AbsHyena absHyena = dog2.GetAbstractAgent<AbsHyena>(); absHyena.self.Names = "抽象鬣狗"; absHyena.self.Age = 6; absHyena.Test(); Console.WriteLine("============================="); } } public class AbsWildDog : AbstractAgent, IAgent<WildDog> { public WildDog self => _self as WildDog; public void Test() { Console.WriteLine("AbsWildDog-Names:" + self?.Names); Console.WriteLine("AbsWildDog-Age:" + self?.Age); Console.WriteLine("AbsWildDog-Height:" + self?.Height); } protected override void Initialize() { Console.WriteLine("AbsWildDog-Initialize方法"); } } public class AbsHyena : AbstractAgent, IAgent<Hyena> { public Hyena self => _self as Hyena; public void Test() { Console.WriteLine("AbsHyena-Names:" + self?.Names); Console.WriteLine("AbsHyena-Age:" + self?.Age); Console.WriteLine("AbsHyena-Height:" + self?.Height); } protected override void Initialize() { Console.WriteLine("AbsHyena-Initialize方法"); } } }
将 Hotfixs 项目生成的 Hotfixs.dll 复制到 HotfixTest 项目中的 Debug 目录下,
运行 HotfixTest 项目,就可以得到下面的输出:
这个框架的逻辑可能稍微有点复杂,多看看就能理解了,下面就开始 Winform 热更功能的实战。
三、Winform 热更新实战
新建一个基于 .Net6 的 Winform 项目,取名:HotfixWinForms,将上面 HotfixTest 项目中的三个文件夹复制过来
将程序设置为 控制台输出
然后在 Form1 界面中,添加四个按钮,
新建一个脚本 PrintBase.cs
namespace HotfixWinForms { public abstract class PrintBase { public abstract void Say1(); public abstract void Say2(); public abstract void Say3(); } }
接着新建脚本 Print.cs
namespace HotfixWinForms { public class Print : PrintBase { public override void Say1() { Console.WriteLine("喜欢唱,跳,rap,篮球"); } public override void Say2() { Console.WriteLine("你干嘛哈哈哎呦"); } public override void Say3() { Console.WriteLine("哎呦哈哈~~"); } } }
接着新建脚本 HotfixBLL.cs ,在 Form1 类中只要调用 PrintBase 的抽象方法即可,具体的内容由子类 Print 去实现,这就是 C# 中多态的常见用法。
namespace HotfixWinForms { public class HotfixBLL { public static PrintBase PrintBases = new Print(); } }
接下来就给 Form1 的四个按钮,添加点击事件。
using ECSharp.Hotfix; namespace HotfixWinForms { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { HotfixBLL.PrintBases.Say1(); } private void button2_Click(object sender, EventArgs e) { HotfixBLL.PrintBases.Say2(); } private void button3_Click(object sender, EventArgs e) { HotfixBLL.PrintBases.Say3(); } private void button4_Click(object sender, EventArgs e) { bool result = HotfixMgr.Load("Hotfix1", "Hotfix1.Main", null, "Hotfix"); Console.WriteLine("加载热重载结果:" + result); } } }
此时,我们运行程序,分别点击按钮1,2,3,输出:
最后一个热更新按钮,先不用管,由于 dll 还没放进来,此时点击会报错,接下来我们就来完成热更新部分。
新建一个基于 .Net6 的 类库 项目,取名:Hotfix1。
将 HotfixWinForms 项目中 Debug 文件夹中的 HotfixWinForms.dll 添加到当前的项目引用。
添加一个脚本 Main.cs
using HotfixWinForms; namespace Hotfix1 { public class Main { public static void Hotfix(string[] args) { HotfixBLL.PrintBases = new HotfixPrint(); Console.WriteLine("重写PrintBases"); } } public class HotfixPrint : PrintBase { public override void Say1() { Console.WriteLine("喜欢,唱,跳,rap,篮球,music,鸡你太美~"); } public override void Say2() { Console.WriteLine("你干嘛~哈哈~哎呦~"); } public override void Say3() { Console.WriteLine("哎呦~啊哈哈~maige"); } } }
写完代码后,点击生成,将生成的 Hotfix1.dll 文件复制到 HotfixWinForms 项目中的 Debug 目录中,那么当前的工作就完成了,接下来就是测试了。
运行 HotfixWinForms 项目,分别的按钮 1、2、3,可以看到,打印和之前一样的,再点击热更新按钮,控制台输出了 “加载热重载结果:True”,说明热更 dll 已经加载成功了,再次分别点击按钮1、2、3,就会发现,打印现在输出的是 Hotfix1 项目中 HotfixPrint 类的打印文字,这就是说明代码成功的实现了热更新,并且,程序也不用关闭。
此时,Hotfix1.dll 载入就相当于给程序打了一个补丁,是可以改变原有逻辑的,而且,在程序运行过程中还可以继续替换,效果和之前一样的。
源码: 点击下载
对源码有疑问的,或不了解的,欢迎私信联系我。
结束
如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢
end
原文链接C# Winform 热更新 基于ECSharp框架_c# 热更新-CSDN博客
猜你喜欢
- 【C#】Winform NanUI 相关功能整合
- 目录NanUI 0.88版本 去掉启动界面(遮罩)NanUI 0.88版本 读取本地资源和嵌入式资源NanUI 0.77版本 打开控制台NanUI 0.77版本 C#调用多个参数的JS方法NanUI 0.77版本 传递数组参数NanUI 0.77版本 设置窗体全屏显示(类似Kiosk模式)NanUI 0.77版本 Bootstrap类 APINanUI 0.88版本 去掉启动界面(遮罩)启动界面是作者给我们显示公司产品的Logo用的,如果用不着可以去掉,但必须要更改源码,如果不想改源码,直接将启
- 【C#】C# Winform 定时清理日志
- 一、前言在 Winform 开发中经常有这样的需求,在用户执行一些操作不正确时,需要将错误信息反馈给用户,比如:登录密码不正确,无法连接到服务器等,一般常见的用法有两个:1.弹框使用 MessageBox.Show("密码错误"); 这样的方式,弹框后,用户必须点击确定后才能执行下一步操作,给用户的体验并不是特别好。2.在界面中显示错误信息,定时清除如果是输入框,直接用 ErrorProvider 控件就行了。如果只是做一些简单的提示信息,那么就要定时清除
- 【C#】C#二分查找(迭代与递归)
- 二分搜索被定义为一种在排序数组中使用的搜索算法,通过重复将搜索间隔一分为二。二分查找的思想是利用数组已排序的信息,将时间复杂度降低到O(log N)。二分查找算法示例 何时在数据结构中应用二分查找的条件: 应用二分查找算法: 1、数据结构必须是有序的。 2、访问数据结构的任何元素都
- 【C#】C# Winform 自定义进度条ProgressBar
- 效果:一、前言Winfrom各种老毛病真的不适合做大型项目,甚至中型项目都不适合,一些小功能都能把你折腾半死,比如,我想在界面上显示一个进度条,用来显示现在硬盘和内存已经使用了多少,使用了 ProgressBar 控件你看看效果:进度条中间一直有个白色光影在晃来晃去的,是不是想让别人感慨:“哇!好强的光芒,我的眼睛快睁不开了...”。而且背景颜色无法改变,这个动画也无法关掉,为了解决这两个问题,我找了很久,终于找到了下面的解决方法。二、自定义进度条于是我在网上找了一些资料,有到效果有,但不是特别
- 【C#】C# Winform DataGridView 控件和 DataTable
- 目录一、概述二、DataTable 的用法1.创建表和列2.添加行3.取值和赋值4.删除行5.遍历 DataTable6.判断 DataTable 列中是否存在某个值7.设置主键8.获取 DataRow 所在的行号9.DataTable 转换为 List10.将 List 转 DataTable三、DataGridView 的用法1.绑定数据2.获取绑定的数据源3.获取 / 设置 选中单元格的数据4.设置单元格的宽高结束一、概述DataGridView 控件提供用于
- 【C#】C# Winfrom 常用功能整合-1
- 目录Winform 最大化遮挡任务栏和全屏显示问题Winfrom 给图片画 矩形,椭圆形,文字Winfrom TabControl选项卡 动态添加,删除,修改Winform ErrorProvider控件Winform 读取Resources图片Winfrom 读取内存条占用大小,硬盘占用大小Winform 全局捕获异常Winform 用线程写入TXT文件,并更新UI和进度Winform 摄像头识别二维码,保存图片Winform 判断窗体是否已打开Winform 动态添加菜单列表,点击切换对应面
- 【C#】C# Winform 三层架构
- 一、介绍三层架构是 C# 桌面开发中比较常用的框架,是由 表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构组成,目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。从三层架构可以看到,很类似于 Web 前端开发的 MVC 框架(视图View,模型Model,控制Contorller),但本质上也有不同的地方,比如都有视图(三层中叫 UI),Mod
- 【C#】C#Windows桌面应用开发实践
- 速览必须功能一览简单下载异步下载如何解决下载文件不完整的问题使用 Downloader 进行 HTTP 多线程下载创建一个下载服务:下载非 HTTP 协议的文件注册表相关的操作(添加与删除)文件占用问题的处理防止重复启动只开一个实例,通用弹窗和提示 使用示例使用 C# 下载文件 (引用自使用 C# 下载文件的十八般武艺)常用接口示例必须功能一览注册表相关的操作(添加与删除) RegistryKey hkm