【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#】C# 开源框架(整理)
- C# 开源框架(整理)Json.NEThttp://json.codeplex.com/Json.Net 是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单。通过Linq To JSON可以快速的读写Json,通过JsonSerializer可以序列化你的.Net对象。让你轻松实现.Net中所有类型(对象,基本数据类型 等)和Json的转换。Math.NEThttp://www.mathdotnet.com/Math.NET的目标是为提供一款
- 【C#】C#的DateTimePicker控件(日期控件)
- 目录一、使用DateTimePicker控件显示时间二、使用DateTimePicker控件以自定义格式显示日期三、返回DateTimePicker控件中选择的日期1.源码2.生成效果 DateTimePicker控件(日期控件)用于选择日期和时间,DateTimePicker控件只能选择一个时间,而不是连续的时间段,也可以直接输入日期和时间。一、使用DateTimePicker控件显示时间
- 【C#】C# Winform Label 控件
- 目录一、概述二、基本用法1.控件内容显示2.控件的外观3.自定义控件的大小4.控件的内边距 5.设置文本的固定位置6.控件的事件结束一、概述Label 控件是 winform 开发中最常用的一个控件,一般用做显示文本,也有时用做打开链接等操作。二、基本用法新建一个 winform 项目,点击 form1 界面,找到工具箱,在工具箱里找到 Label ,拖入到界面即可。1.控件内容显示label 拖入界面中,如下,单击在属性界面就能看到具体的控件属性在这里有两个重要的属性:1.Name在
- 【C#】C# Winform 配置文件App.config
- 目录一、简介二、添加引用 三、添加节点1.普通配置节点2.数据源配置节点四、管理类 ConfigHelper.cs1.获取配置节点2.更新或加入配置节点结束一、简介在C#中,配置文件很常用,ASP.NET 和 Winform 名称不同,用法一样,如下图config 文件通常用来存储一些需要修改的数据,比如用户名密码,连接数据库的IP地址等,而不是在代码中写死。有人可能会问,那我自己自定义一个配置文件也行,为什么要用它这个?区别当然有,微软自己封装的读取和写入会更简单一些,你自己封装的,
- 【C#】从零开始用C#写一个桌面应用程序(一)基础操作
- 准备winform应用程序编写桌面应用客户端的技术。xaml一种标记语言。winform程序组成。 程序入口: form.cs和它的设计文件: 启动的过程以及涉及的文件:main函数: form1的构造函数和它的设计文件: main-》构造form-》initializeComponent-》 拖入一个 button控件可以看到: 这时我们已经梳理启动过程。使用组件的方法 可以在
- 【C#】C# 解压zip文件,并覆盖
- 使用ZipFile.ExtractToFile方法,并将overwrite参数设置为true,这样可以覆盖同名的目标文件。代码如下:using System; using System.IO; using System.IO.Compression; namespace ConsoleApplication { class Program &nbs
- 【C#】C# Winform 文本面板带滚动条
- 在PC软件开发中经常有这样的需求,需要在一个固定大小的面板中显示一些内容,并且面板能上下拖动,将所有的内容完整的展示,有点类似网页上看新闻,如果要在 winfrom 中要如何实现的呢,下面就演示如何实现的吧效果:1.新建一个winform 项目,在界面中拖入一个Panel 将 panel1 的 AutoScroll 设置为 True2.再次拖入一个 Panel ,将高度拉长,这时就自动出现了滚动条,只是此时里面还没有任何内容,下面就在 panel2 中加入一点内容。
- 【C#】Winform解决方案打包成.exe 安装版Windows桌面应用程序
- 踩了几天的坑,慢慢爬出来了。帮助一下新手友人吧,高手请绕路。IDE Version:Visual Studio 20191.安装Microsoft Visual Studio Installer Project(1)打开Visual Studio 2019,扩展->管理扩展(2)搜索install,下载图中的扩展即可(我已经安装了,所以没有下载按钮)按照操作安装即可2.打包(1)右键 解决方案->添加->新建项目(2)搜索setup->选择 Setup Project-&