目录

一、简介

二、 ECSharp热更新演示

三、Winform 热更新实战

结束


不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

不推荐使用

一、简介

不久之前我写过一篇 Winform 自动更新的帖子,虽然很方便,但也有个问题,那就是如果程序运行中出现了错误,那么必须重启客户端,才能更新到最新的版本,如果程序正在运行中,是无法动态的去改变原有的逻辑的。

有人可能会说,这有什么难的,我自己写个 dll,将这个 dll 添加到项目的引用中,运行程序后,把 dll 给替换掉,逻辑不就变了嘛?这个方案没毛病,但它也有个问题,程序运行后,这时 dll 已经被占用了,没办法替换了,如下图:

后面,我在 github 发现了一个开源框架 ECSharp ,这个框架是有热更新的功能的,于是我试了一下,发现确实可以通过替换dll方式来实现热更新,而且在程序运行过程中,随便怎么替换 dll,都不会有文件占用问题,下面就根据官方的一些简介:

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.事件与命令

二、 ECSharp热更新演示

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

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

上图的代码中,Player.cs 是用来测试的,Program.cs 是创建项目时默认生成的。

下面的代码有些混乱,这只是Demo,当时也是用来测试功能的

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 载入就相当于给程序打了一个补丁,是可以改变原有逻辑的,而且,在程序运行过程中还可以继续替换,效果和之前一样的。

另外,如果有兴趣可以使用下面的 NLua 热更新,这个帖子有一个完整的Demo,虽然没写的那么好,但也是展现了一个热更基本的流程,而且功能更加强大,也不用去打DLL补丁那么繁琐,只是还没测试他的稳定性,有用在工作中的可以留言说下感受。

C# NLua Winform 热更新-CSDN博客

结束

如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢

end

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐