您的当前位置:首页>全部文章>文章详情

【C#】C# Winform 热更新 基于ECSharp框架

CrazyPanda发表于:2024-02-05 23:46:07浏览:305次TAG:

目录

一、简介

二、 ECSharp热更新演示

三、Winform 热更新实战

结束




一、简介

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 已经被占用了,没办法替换了,如下图:

1.png

后面,我发现了 ECSharp 这个框架是可以解决文件占用问题,而且在程序运行过程中,随便怎么替换 dll,都不会有文件占用问题,并且还是开源的,可以知道具体是怎么实现的,那么下面就根据官方的资料看看是如何做到热更新的吧。


二、 ECSharp热更新演示

首先,在 Github 上把 ECSharp 源码下载到本地,因为我在项目中,是直接复制官方的源码,或者,你也可以在 NuGet 上安装 EasySharpFrame 插件也是一样的。

新建一个居于 .NET6 框架的控制台项目,取名:HotfixTest,将 ECSharp 部分源码复制过来,添加到项目中,如下图:

1.png

在 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 就好了,如下图:

1.png

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 项目,就可以得到下面的输出:

1.png

这个框架的逻辑可能稍微有点复杂,多看看就能理解了,下面就开始 Winform 热更功能的实战。


三、Winform 热更新实战

新建一个基于 .Net6 的 Winform 项目,取名:HotfixWinForms,将上面 HotfixTest 项目中的三个文件夹复制过来

1.png

将程序设置为 控制台输出

1.png

 然后在 Form1 界面中,添加四个按钮,

1.png

 新建一个脚本 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,输出:

1.png

最后一个热更新按钮,先不用管,由于 dll 还没放进来,此时点击会报错,接下来我们就来完成热更新部分。


新建一个基于 .Net6 的 类库 项目,取名:Hotfix1。

将 HotfixWinForms 项目中 Debug 文件夹中的 HotfixWinForms.dll 添加到当前的项目引用。

1.png

添加一个脚本 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 目录中,那么当前的工作就完成了,接下来就是测试了。

1.png


运行 HotfixWinForms 项目,分别的按钮 1、2、3,可以看到,打印和之前一样的,再点击热更新按钮,控制台输出了 “加载热重载结果:True”,说明热更 dll 已经加载成功了,再次分别点击按钮1、2、3,就会发现,打印现在输出的是 Hotfix1 项目中 HotfixPrint 类的打印文字,这就是说明代码成功的实现了热更新,并且,程序也不用关闭。

1.png

此时,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的目标是为提供一款
发表于:2024-01-30 浏览:344 TAG:
【C#】C#的DateTimePicker控件(日期控件)
目录一、使用DateTimePicker控件显示时间二、使用DateTimePicker控件以自定义格式显示日期三、返回DateTimePicker控件中选择的日期1.源码2.生成效果&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DateTimePicker控件(日期控件)用于选择日期和时间,DateTimePicker控件只能选择一个时间,而不是连续的时间段,也可以直接输入日期和时间。一、使用DateTimePicker控件显示时间&nbsp;
发表于:2024-01-29 浏览:391 TAG:
【C#】C# Winform Label 控件
目录一、概述二、基本用法1.控件内容显示2.控件的外观3.自定义控件的大小4.控件的内边距&nbsp;5.设置文本的固定位置6.控件的事件结束一、概述Label 控件是 winform 开发中最常用的一个控件,一般用做显示文本,也有时用做打开链接等操作。二、基本用法新建一个 winform 项目,点击 form1 界面,找到工具箱,在工具箱里找到 Label ,拖入到界面即可。1.控件内容显示label 拖入界面中,如下,单击在属性界面就能看到具体的控件属性在这里有两个重要的属性:1.Name在
发表于:2024-02-04 浏览:300 TAG:
【C#】C# Winform 配置文件App.config
目录一、简介二、添加引用&nbsp;三、添加节点1.普通配置节点2.数据源配置节点四、管理类 ConfigHelper.cs1.获取配置节点2.更新或加入配置节点结束一、简介在C#中,配置文件很常用,ASP.NET 和 Winform 名称不同,用法一样,如下图config 文件通常用来存储一些需要修改的数据,比如用户名密码,连接数据库的IP地址等,而不是在代码中写死。有人可能会问,那我自己自定义一个配置文件也行,为什么要用它这个?区别当然有,微软自己封装的读取和写入会更简单一些,你自己封装的,
发表于:2024-01-31 浏览:385 TAG:
【C#】从零开始用C#写一个桌面应用程序(一)基础操作
准备winform应用程序编写桌面应用客户端的技术。xaml一种标记语言。winform程序组成。&nbsp;程序入口:&nbsp;form.cs和它的设计文件:&nbsp;&nbsp;启动的过程以及涉及的文件:main函数:&nbsp;form1的构造函数和它的设计文件:&nbsp;&nbsp;&nbsp; main-》构造form-》initializeComponent-》&nbsp;拖入一个 button控件可以看到:&nbsp;这时我们已经梳理启动过程。使用组件的方法&nbsp;可以在
发表于:2024-01-30 浏览:498 TAG:
【C#】C# 解压zip文件,并覆盖
&nbsp;使用ZipFile.ExtractToFile方法,并将overwrite参数设置为true,这样可以覆盖同名的目标文件。代码如下:using&nbsp;System; using&nbsp;System.IO; using&nbsp;System.IO.Compression; &nbsp; namespace&nbsp;ConsoleApplication { &nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;Program &nbsp;&nbsp;&amp;nbs
发表于:2024-01-29 浏览:591 TAG:
【C#】C# Winform 文本面板带滚动条
在PC软件开发中经常有这样的需求,需要在一个固定大小的面板中显示一些内容,并且面板能上下拖动,将所有的内容完整的展示,有点类似网页上看新闻,如果要在 winfrom 中要如何实现的呢,下面就演示如何实现的吧效果:1.新建一个winform 项目,在界面中拖入一个Panel&nbsp;将 panel1 的&nbsp;AutoScroll 设置为 True2.再次拖入一个&nbsp;Panel ,将高度拉长,这时就自动出现了滚动条,只是此时里面还没有任何内容,下面就在 panel2 中加入一点内容。
发表于:2024-02-03 浏览:330 TAG:
【C#】Winform解决方案打包成.exe 安装版Windows桌面应用程序
踩了几天的坑,慢慢爬出来了。帮助一下新手友人吧,高手请绕路。IDE Version:Visual Studio 20191.安装Microsoft Visual Studio Installer Project(1)打开Visual Studio 2019,扩展-&gt;管理扩展(2)搜索install,下载图中的扩展即可(我已经安装了,所以没有下载按钮)按照操作安装即可2.打包(1)右键 解决方案-&gt;添加-&gt;新建项目(2)搜索setup-&gt;选择 Setup Project-&amp;
发表于:2024-01-28 浏览:481 TAG:
【C#】C#md5加密
using&nbsp;System; using&nbsp;System.Collections.Generic; using&nbsp;System.Linq; using&nbsp;System.Security.Cryptography; using&nbsp;System.Text; using&nbsp;System.Threading.Tasks; &nbsp; namespace&nbsp;mdstr { &nbsp;&nbsp;&nbsp;&nbsp;internal&nbsp;
发表于:2024-01-30 浏览:279 TAG:
【C#】C# Winfrom 常用功能整合-1
目录Winform 最大化遮挡任务栏和全屏显示问题Winfrom 给图片画 矩形,椭圆形,文字Winfrom TabControl选项卡 动态添加,删除,修改Winform ErrorProvider控件Winform 读取Resources图片Winfrom 读取内存条占用大小,硬盘占用大小Winform 全局捕获异常Winform 用线程写入TXT文件,并更新UI和进度Winform 摄像头识别二维码,保存图片Winform 判断窗体是否已打开Winform 动态添加菜单列表,点击切换对应面
发表于:2024-02-02 浏览:409 TAG: