C# NLua Winform 热更新

一、概述

NLua 是一个用于 .NET 平台的 Lua 脚本绑定库。它允许在 C# 代码中嵌入 Lua 脚本,并允许两者之间进行交互。NLua 的主要特点包括:

  1. 轻量级:NLua 是一个轻量级的库,易于集成到现有的 .NET 项目中。
  2. 动态类型:Lua 是动态类型的语言,这意味着变量的类型可以在运行时改变。
  3. 灵活的绑定:NLua 提供了灵活的绑定机制,使得 C# 和 Lua 之间的数据交互变得简单。
  4. 丰富的 API:NLua 提供了丰富的 API,以便在 Lua 脚本中调用 .NET 的类和方法。
  5. 调试支持:NLua 支持调试功能,方便开发者在 Lua 脚本中设置断点、单步执行等操作。
  6. 社区支持:NLua 有一个活跃的社区,为开发者提供了一个交流和寻求帮助的平台。

使用 NLua,你可以在 .NET 应用中轻松地嵌入 Lua 脚本,从而实现动态逻辑、配置管理、插件系统等功能。通过 NLua,你可以利用 Lua 的灵活性和易用性,同时保持 .NET 的强大功能和性能。

NLua 支持 UWP、Windows、Linux、Mac、iOS、Android 平台。

NLua 源码和示例 Github 地址

GitHub - NLua/NLua: Bridge between Lua and the .NET.

二、创建项目

创建一个 .NET Framework  Winform 项目,这里我用的版本是 4.8.1,取名叫 NLuaDemo,在 NuGet 中安装 NLua 包。

winform 界面设计如下:

为了先看看 NLua 到底有没有效果,先做一个小案例,让你先熟悉一下 NLua 框架,在后面的案例中,会有完整的热更新方式展示。

需求:用 Lua 脚本来改变 Winform 界面中的抽奖人数,数量随意。

1.添加一个类 PublicData ,这个类用来保存公共数据(在第三节的案例中,这个类将不再使用)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class PublicData
{
    public static NLuaDemo.Form1 Form1s { get; set; }
}

我将 From1 保存在这里,主要是为了方便后面 Lua 调用。

2.将 Form1.Designer.cs 中的控件设置为 public,以便让 Lua 能直接调用 winform 控件。

3.将 Program 类改为如下(适用当前的 demo,在第三节的案例中,不再使用这种写法)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace NLuaDemo
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            PublicData.Form1s = new Form1();
            Application.Run(PublicData.Form1s);
        }
    }
}

4.Form1 代码如下(第三节案例中,代码会不一样)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NLua;

namespace NLuaDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Lua Luas = new Lua();
        //lua 脚本的地址
        private string LuaPath;

        private void Form1_Load(object sender, EventArgs e)
        {
            Luas.State.Encoding = Encoding.UTF8;
            LuaPath = $"{Application.StartupPath}\\main.lua";
            LoadLua();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Luas.Close();
        }

        //热重载
        private void Button_HotUpdate_Click(object sender, EventArgs e)
        {
            Luas.DoString("update()");
        }

        private void LoadLua()
        {
            if (File.Exists(LuaPath))
            {
                Luas.LoadCLRPackage();
                Luas.DoFile(LuaPath);
                Luas["form1s"] = PublicData.Form1s;
            }
        }
    }
}

5.在项目的 Debug 目录中,新建一个 main.lua 文件,加入下面代码

form1s = {};

function update()
    form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;
end

完成了上面的工作,现在可以开始测试了

可以看到,Lua 脚本确实改变了 winform 界面的数据。

这里为什么不把逻辑直接写在 main.lua 中呢?

form1s = {};

form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;

function update()
    form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;
end

因为运行后就会报错:

由于 Lua 脚本在运行后,会执行所有的代码,但是我们定义的 Lua 全局变量此时还没有赋值,直接运行当然报错了,于是我将热更新内容写入到 lua 脚本中的 update 方法中,等 C# 这边初始化完成后,调用 update 方法就不会有问题了。

另外还有一种方法,使用 LoadFile 方法,我试了一下,没有效果,可能是我用法不对

LuaFunction luaFunction = Luas.LoadFile("C:\\test.lua");

有兴趣的朋友可以去试试,有好的建议欢迎留言评论。

三、实现 Lua 热更新

在上面的案例中,我们是把 Form1 赋值给了 lua 脚本中的 form1s 这个变量(也可以叫表单),其实还可以这么写:

private void LoadLua()
{
    if (File.Exists(LuaPath))
    {
        Luas.LoadCLRPackage();
        Luas.DoFile(LuaPath);
        Luas["this"] = this;
    }
}

但是这种用法在 Lua 脚本用会有错误,在 Visual Studio Code 中搭建好 Lua 开发环境,就会看到提示:未定义的全局变量 “this”

这个不用管它,lua 脚本只要在 C# 项目中运行不报错就行了。

这里的写法改变后,上一个 demo 中代码也要改改了。

1.Program 类恢复默认的写法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace NLuaDemo
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //PublicData.Form1s = new Form1();
            //Application.Run(PublicData.Form1s);
            Application.Run(new Form1());
        }
    }
}

2.PublicData 类可以删掉,或者注释所有的代码,现在用不上了。

另一个,Lua 调用 C# 方法,要用英文的冒号去调用方法,而不是像 C# 一样用点去调用,这个在 Unity3d 中 XLua 等热更新框架是同样的用法,具体用法可以参考下面 main.lua 代码。

--import("System")
--import('System.Windows.Forms')
--import("System.Threading");

--form1s = {};

--奖品
prize = {"手机", "电脑", "耳机", "鼠标", "键盘", "充电宝"}
--抽奖人
participant = {"张三", "李四", "老王", "狗蛋", "铁剩"}

--热重载
function update()
    this:Print("抽奖人 长度是:" .. #participant)
    this.Label_RaffleNumber.Text = "抽奖人数:" .. #participant
    this.Label_PrizesNum.Text = "奖品数:" .. #prize

    --奖品下拉框
    this.ComboBox_Prize.Items:Clear()
    for i,item in ipairs(prize) do
        this.ComboBox_Prize.Items:Add(item)
    end
    this.ComboBox_Prize.SelectedIndex = 0

    --抽奖人下拉框
    this.ComboBox_LotteryGiver.Items:Clear();
    for i,item in ipairs(participant) do
        this.ComboBox_LotteryGiver.Items:Add(item);
    end   
    this.ComboBox_LotteryGiver.SelectedIndex = 0
end

--抽奖按钮
function raffle()
    --随机奖品
    local prizeIndex = math.random(1, #prize) 
    local prize = prize[prizeIndex] 

    --随机抽奖人
    local participantIndex = math.random(1, #participant) 
    local participant = participant[participantIndex] 

    local content = "抽奖人:"..participant..",获得奖品:"..prize
    this:Print(content) 
end

注意上面 lua 脚本中的 Label_RaffleNumber,Label_PrizesNum,ComboBox_Prize 等关键字,这都是 winform 的控件,如果你用的不是我的源码,winform 控件名和 lua 脚本中的也不一致,那么运行就会报错:

错误:

当前 demo 所有的控件名

winform 这个控制台不知道怎么回事,lua 中打印用的 print 方法打印出来全是乱码,但是 winform 控件使用 lua 脚本中的中文还是正常的。

后面我只能在 Form1 中添加一个 Print 方法,这样打印才是正常的。

Form1代码:

using NLua;
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace NLuaDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Lua Luas = new Lua();
        //lua 脚本的地址
        private string LuaPath;

        private void Form1_Load(object sender, EventArgs e)
        {
            Luas.State.Encoding = Encoding.UTF8;
            LuaPath = $"{Application.StartupPath}\\main.lua";
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Luas.Close();
        }

        //热重载 点击事件
        private void Button_HotUpdate_Click(object sender, EventArgs e)
        {
            LoadLua();
            Luas.DoString("update()");
        }

        //抽奖 点击事件
        private void Button_Raffle_Click(object sender, EventArgs e)
        {
            Luas.DoString("raffle()");
        }

        //加载 lua 脚本
        private void LoadLua()
        {
            if (File.Exists(LuaPath))
            {
                Luas.LoadCLRPackage();
                Luas.DoFile(LuaPath);
                Luas["this"] = this;
            }
        }

        //lua 打印用的
        public void Print(string text)
        {
            Console.WriteLine(text);
        }
    }
}

运行后,点击 “热重载” 按钮,就会看到奖品和抽奖人都有那些内容,这些都是由 lua 进行赋值的。

点击 “抽奖” 按钮,就可以看到当前的中奖人和奖品

既然是热更新,那我在运行过程中改变代码可以么?当然可以!

我们把 lua 脚本中抽奖人和奖品表单删除一部分,改完后记得保存,如下:

--奖品
prize = {"手机", "电脑", "耳机", "鼠标"}
--抽奖人
participant = {"张三", "李四", "老王"}

再次点击 “热重载” 按钮,这时界面就发生了一些变化

抽奖人和奖品都少了

NLua 其实还有很多其他的用法,这里就没一一展示了。

上面的代码就是当前项目所有的代码了,创作不易,如果你觉得我的帖子对你有所帮助,也可以通过下载源码的方式来支持我,在此谢谢了。

源码:点击下载

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年【裂解(裂化)工艺】考试报名及裂解(裂化)工艺考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 裂解&#xff08;裂化&#xff09;工艺考试报名考前必练&#xff01;安全生产模拟考试一点通每个月更新裂解&#xff08;裂化&#xff09;工艺考试总结题目及答案&#xff01;多做几遍&#xff0c;其实通过裂解&#…

Tuxera NTFS for Mac2024免费Mac读写软件下载教程

在日常生活中&#xff0c;我们使用Mac时经常会遇到外部设备不能正常使用的情况&#xff0c;如&#xff1a;U盘、硬盘、软盘等等一系列存储设备&#xff0c;而这些设备的格式大多为NTFS&#xff0c;Mac系统对NTFS格式分区存在一定的兼容性问题&#xff0c;不能正常读写。 那么什…

如何从 DSA 切换到 PMax 以使您的 Google 付费广告面向未来

为了在 Google Ads 不可避免的过渡期之前&#xff0c;我们将介绍如何从动态搜索广告切换到效果最大化广告 如何从 DSA 切换到 PMax 以使您的 Google 付费广告面向未来 变化是唯一不变的&#xff0c;尤其是在数字广告中——您可能听说过一些关于动态搜索广告 &#xff08;DSA&…

第27关 在K8s集群上使用Helm3部署最新版本v2.10.0的私有镜像仓库Harbor

------> 课程视频同步分享在今日头条和B站 大家好&#xff0c;我是博哥爱运维。 在前面的几十关里面&#xff0c;博哥在k8s上部署服务一直都是用的docker hub上的公有镜像&#xff0c;对于企业服务来说&#xff0c;有些我们是不想把服务镜像放在公网上面的&#xff1b; 同时…

25、Qt设备识别(简单的密钥生成器)

一、说明 在很多商业软件中&#xff0c;需要提供一些可以试运行的版本&#xff0c;这样就需要配套密钥机制来控制&#xff0c;纵观大部分的试用版软件&#xff0c;基本上采用以下几种机制来控制。 1、远程联网激活&#xff0c;每次启动都联网查看使用时间等&#xff0c;这种方…

顶配版SAM:由分割一切迈向感知一切

文章目录 0. 前言1. 论文地址1.1 项目&代码1.2 模型地址1.3 Demo 2. 模型介绍2.1 亮点2.2 方法 3. 量化结果、可视化展示Reference 0. 前言 现有的视觉分割基础模型&#xff0c;如 SAM 及其变体&#xff0c;集中优势在形状、边缘等初级定位感知&#xff0c;或依赖外部模型…

【Android】使用android studio查看内置数据库信息

背景 需要用到android db 逻辑存储用户信息等等。 使用 在 App inspection 工具中查看该 app 内的 db 数据 sql执行 在新的查询框内解析查询即可知道当前的数据信息。 官方文档-使用 Database Inspector 调试数据库

【计算机毕业设计】SSM医疗药品采购系统

项目介绍 ssm医疗药品采购系统。主要功能有&#xff1a; 用户管理&#xff1a;管理员列表&#xff1b; 采购管理&#xff1a;采购列表&#xff1b; 药品出库&#xff1a;药品出库&#xff1b; 库存管理&#xff1a;库存统计&#xff1b; 数据维护&#xff1a;药品列表、仓库…

【Unity入门】PlayerPrefs的简介与使用

目录 PlayerPrefs储存位置用例注意事项 PlayerPrefs PlayerPrefs 是Unity内置的一个静态类&#xff0c;可以用于存储一些简单的数据类型&#xff1a;int ,string ,float。 分别对应的函数为&#xff1a; SetInt()&#xff1a;保存整型数据GetInt()&#xff1a;读取整形数据Se…

MSF(Metasploit Framework)详细教程

一. 简介 Metasploit 是一个开源的渗透测试开源软件&#xff0c;也是一个逐步发展成熟的漏洞研究与渗透测试代码开发平台&#xff0c;此外也将成为支持整个渗透测试过程的安全技术集成开发与应用环境&#xff0c;2009年10月&#xff0c;Metasploit项目被一家渗透测试技术领域的…

GO学习记录

一、Go语言的源文件的拓展是.go 开发环境和工具&#xff1a;GOLAND 个人版开发&#xff1a; 企业版开发&#xff1a; 二、Go语言结构 1、package main 定义一个名为main的包名 2、import "fmt" 添加fmt包 3、func main() 是程序开始执行的函数 4、定义变量&a…

《对话品牌》——活到老“养”到老

本期节目《对话品牌》栏目组邀请到了深圳壹常青健康管理有限公司董事长邬锡娣女士参加栏目录制&#xff0c;分享其企业故事&#xff0c;树立品牌形象&#xff0c;提升品牌价值&#xff01; 节目嘉宾&#xff1a;邬锡娣女士 节目主持人&#xff1a;董倩 节目播出平台&#xf…

【K8S 二进制部署】部署单Master Kurbernetes集群

目录 一、基本架构和系统初始化 1、集群架构&#xff1a; 2、操作系统初始化配置&#xff1a; 2.1、关闭防火墙和安全机制&#xff1a; 2.2、关闭swap 2.3、根据规划设置主机名 2.4、三台主机全部互相映射 2.5、调整内核参数 3、时间同步&#xff08;所有节点时间必须同…

iframe展示pdf、png、jpg

iframe展示pdf、png、jpg&#xff1a; 1、前端定义div&#xff1a; <div id"pdf-container"></div>/*dpf的div*/ <iframe id"imageFrame"></iframe>/*图片的div*/2、后端查询base64的流&#xff0c;前端页面初始化js方法&#x…

upset 绘制

好久没有更新,今天来一个upset图的绘制 1.1 安装包 #绘制upset的包现在看来有三个 ## UpSet ### 最基本的upsetR包,使用方便,但是扩展不方便 devtools::install_github("hms-dbmi/UpSetR") ## complex-upset ### UpSet的升级款 支持ggplot2 devtools::install_git…

什么是服务器迁移?

服务器迁移一般来说是将物理服务器从一个地点&#xff08;物理机房&#xff09;移动到另一个地点&#xff0c;或将数据从一台服务器移动到另一台服务器的过程。 机房搬迁&#xff1a;当公司办公场所发生变化&#xff0c;原有机房无法继续使用时&#xff0c;需要将服务器迁移到…

计算机报错x3daudio1_7.dll怎么修复,其实很简单

游戏已经成为了人们休闲娱乐的重要方式之一。然而&#xff0c;有时候我们在玩游戏的过程中会遇到一些错误提示&#xff0c;比如“玩游戏报错x3daudio1_7.dll怎么办”。这个问题可能会导致游戏无法正常运行等问题。x3daudio1_7.dll是DirectX Audio API的一部分&#xff0c;它是D…

腾讯云跨云迁移工具案例实践:阿里云迁移到腾讯云

对于阿里云批量迁移到腾讯云&#xff0c;HyperMotion可以支持批量一键式安装Agent软件&#xff0c;做到了操作步骤简单化、自动化&#xff0c;可以满足常见源端操作系统类型。 例如&#xff1a;Windows 2003-2019&#xff0c;CentOS、RedHat 6.x-7.x、Ubuntu 14.x - 16.x、SUS…

为什么TCP会粘包

硬核图解|tcp为什么会粘包&#xff1f;背后的原因让人暖心 数据包报文格式&#xff08;IP包、TCP报头、UDP报头&#xff09; TCP&#xff0c;Transmission Control Protocol。传输控制协议&#xff0c;是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP粘包是指发…

【五】【C语言\动态规划】删除并获得点数、粉刷房子、买卖股票的最佳时机含冷冻期,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…