ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

xLua 核心 API 全解析:从 C 调用 Lua 到类型映射与内置宏

xLua 核心 API 全解析:从 C 调用 Lua 到类型映射与内置宏 xLua 核心 API 全解析从 C# 调用 Lua 到类型映射与内置宏【免费下载链接】xLuaxLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc.项目地址: https://gitcode.com/gh_mirrors/xl/xLua导读本文以 xLua 官方 API 参考文档XLua_API_EN.md为主线系统讲解 xLua 的 C# 侧核心 APILuaEnv、LuaTable、LuaFunction、Lua 侧访问 C# 对象的语法CS.命名空间、uint64、xlua.*工具函数、cast、C# 与 Lua 的类型映射规则以及三个重要的编译期宏。读完本文你将掌握在 Unity/.NET 工程中用 xLua 执行 Lua 代码、读写 Lua 数据、调用 Lua 函数、在 Lua 中操作 C# 对象并正确选择值类型传递与避免装箱开销的完整实战方案。文章同时结合仓库源码LuaEnv.cs、LuaTable.cs、LuaFunction.cs、StaticLuaCallbacks.cs 等对 API 的底层实现与调用链进行佐证方便读者按图索骥深入阅读。一、C# 侧核心 APIxLua 的 C# 侧 API 围绕三个核心类型展开LuaEnvLua 虚拟机环境的封装、LuaTableLua 表的封装、LuaFunctionLua 函数的封装。以下 API 的签名与行为均以 XLua_API_EN.md 为准并结合源码实现说明底层细节。1.1 LuaEnv 类型虚拟机生命周期管理LuaEnv是 xLua 中最顶层的类型一个实例对应一个独立的 Lua 运行时环境。其核心成员在源码 LuaEnv.cs 中均有对应实现。object[] DoString(string chunk, string chunkName chunk, LuaTable env null)功能执行一段 Lua 代码块。参数chunkLua 代码字符串chunkName出错时用于调试信息定位指明错误发生在哪个代码块的哪一行env该代码块的执行环境环境变量表。返回值代码块中return语句的返回值。例如代码块return 1, helloDoString返回的数组将包含两个对象一个是double类型的1另一个是字符串hello。示例LuaEnv luaenv new LuaEnv(); object[] ret luaenv.DoString(print(hello)\r\nreturn 1); UnityEngine.Debug.Log(ret ret[0]); luaenv.Dispose();源码印证在 LuaEnv.cs 中DoString(string ...)先将字符串按 UTF-8 编码为字节数组再转调DoString(byte[] ...)字节数组版本内部依次执行xluaL_loadbuffer加载字节码/源码、lua_pcall保护模式调用成功后将栈顶的LUA_MULTRET多返回值通过translator.popValues弹出为object[]。env参数通过lua_setfenv设置为该 chunk 的环境。T LoadStringT(string chunk, string chunkName chunk, LuaTable env null)功能加载编译一段代码块但不执行返回代表该代码块的委托delegate或LuaFunction。参数与DoString相同T必须是委托类型或LuaFunction。返回值代表该代码块的委托或LuaFunction类型实例。源码印证LuaEnv.cs 中LoadStringT首先校验T必须是LuaFunction或Delegate的子类否则抛出InvalidOperationException然后同样走xluaL_loadbuffer加载 chunk经translator.GetObject转换为目标委托类型。仓库还提供了LoadString(byte[] chunk, ...)重载与直接返回LuaFunction的便捷重载适合加载预编译的 Lua 字节码。LuaTable Global功能代表 Lua 全局环境_G的LuaTable。源码印证LuaEnv.cs 中Global属性直接返回内部维护的_G字段可借助它读写全局变量。void Tick()功能清理未被手动释放的 Lua 侧LuaBase对象如LuaTable、LuaFunction等需要在MonoBehaviour的Update中等周期性地调用。源码印证LuaEnv.cs 中Tick()从refQueue队列中逐条取出GCAction并调用translator.ReleaseLuaBase释放 Lua 引用在非XLUA_GENERAL即 Unity 环境下还会通过translator.objects.Check对 C# 对象进行有效性检查默认每 tick 最多检查 20 个对象用于检测已销毁的UnityEngine.Object避免悬空引用。void AddLoader(CustomLoader loader)功能添加自定义 loader加载器。当 Lua 中执行require需要某个文件时注册的 loader 会被回调。参数loader是委托类型byte[] CustomLoader(ref string filepath)。loader 找到文件后将其读入内存并以字节数组返回如果需要支持调试定位应把filepath设置为 IDE 可以找到的路径相对或绝对。源码印证委托定义于 LuaEnv.csAddLoader内部调用AddSearcher将 loader 插入到package.loadersLua 5.3 为package.searchers的加载器链表中从而参与require的查找流程。void Dispose()功能销毁该LuaEnv实例释放 Lua 虚拟机相关资源。LuaEnv 使用建议原文强调全局只使用一个实例在Update中调用 GC 方法Tick不再需要时调用Dispose。1.2 LuaTable 类型Lua 表的 C# 封装LuaTable的底层实现位于 LuaTable.cs它继承自LuaBase内部通过lua_getref/lua_gettop等 Lua C API 与虚拟机交互并提供了“无装箱no boxing”的泛型版本读写接口。T GetT(string key)功能读取key对应的值并转换为类型T若键不存在或类型不匹配返回null。注意在 LuaTable.cs 中若取到nil且TValue是值类型会抛出InvalidCastException提示can not assign nil to ...因此读取值类型字段前需确保 Lua 侧确实存在该键。T GetInPathT(string path)功能与Get的区别在于会解析路径中的.。例如var i tbl.GetInPathint(a.b.c)等价于执行 Lua 代码i tbl.a.b.c。避免多次调用Get与获取中间变量执行效率更高。源码印证LuaTable.cs 中GetInPath调用xlua_pgettable_bypath这一原生扩展接口一次调用完成多层路径的查表。void SetInPathT(string path, T val)功能GetInPathT对应的 setter按路径设置嵌套字段的值。源码印证LuaTable.cs 中通过xlua_psettable_bypath一次完成多层路径赋值。void GetTKey, TValue(TKey key, out TValue value)功能上面 API 的 key 只支持string本 API 对 key 类型无此限制可使用任意类型作为键out参数接收取出的值。源码印证LuaTable.cs 中GetTKey, TValue通过translator.PushByType压入任意类型的 key再调用xlua_pgettable完成取表。void SetTKey, TValue(TKey key, TValue value)功能GetTKey, TValue对应的 setter。源码印证LuaTable.cs 中通过xlua_psettable完成赋值出错时抛出让调用方能感知的 Lua 异常。T CastT()功能将表转换为类型T。T可以是声明了CSharpCallLua的接口、带默认构造函数的类型或结构体、Dictionary、List等。源码印证LuaTable.cs 中CastT通过translator.GetObject将 Lua 栈上的 table 转换为目标 C# 类型。void SetMetaTable(LuaTable metaTable)功能为表设置 metatable元表。补充配合 LuaTable.cs 中的GetMetaTable可读写元表用于自定义表的__index、__call等行为。1.3 LuaFunction 类型Lua 函数的 C# 封装性能提示原文强调通过LuaFunction访问 Lua 函数存在装箱/拆箱开销。若需要频繁调用不建议使用该类型推荐用table.GetABCDelegate获取 C# 委托后再调用假设ABCDelegate是 C# 委托类型。使用table.GetABCDelegate之前需将ABCDelegate加入生成代码列表详见 custom_generate.md。object[] Call(params object[] args)功能以可变参数调用 Lua 函数返回调用的返回值数组。源码印证LuaFunction.cs 中转调Call(args, null)核心实现通过lua_pcall执行函数translator.popValues弹出所有返回值。object[] Call(object[] args, Type[] returnTypes)功能调用 Lua 函数并显式指定每个返回值的类型系统按指定类型自动转换。源码印证LuaFunction.cs 中若returnTypes非空则popValues(L, oldTop, returnTypes)按类型数组逐项转换返回值。void SetEnv(LuaTable env)功能等价于 Lua 的setfenv函数为函数设置新的环境表。源码印证LuaFunction.cs 中通过lua_setfenv实现可用于构造沙箱环境。二、Lua 侧访问 C# 对象CS APIxLua 在 Lua 侧提供了CS全局命名空间用于直接访问 C# 类型与成员。相关回调注册于 ObjectTranslator.cs 的OpenLib方法以及 StaticLuaCallbacks.cs 中。2.1 类型构造、静态成员与枚举CS.namespace.class(...)调用 C# 类型构造函数返回实例local v1 CS.UnityEngine.Vector3(1, 1, 1)CS.namespace.class.field访问 C# 静态成员print(CS.UnityEngine.Vector3.one)CS.namespace.enum.field访问枚举值-- 例如CS.UnityEngine.KeyCode.A、CS.UnityEngine.TextAnchor.MiddleCenter 等2.2typeof函数类似 C# 的typeof关键字返回Type对象。典型场景是GameObject.AddComponent这类需要Type参数的重载newGameObj:AddComponent(typeof(CS.UnityEngine.ParticleSystem))2.3 无符号 64 位整数支持uint64Lua 5.3 的整数类型为有符号 64 位无法直接完整表达ulong。xLua 为此提供了uint64工具表其实现依赖 LuaDLL.cs 中的lua_pushuint64、lua_touint64、lua_isuint64等原生接口并在 ObjectCasters.cs 中为ulong注册了专用类型检查器既接受普通 number也接受 uint64 userdata。可用的函数如下| 函数 | 功能 | | - | - | |uint64.tostring| 无符号数转字符串 | |uint64.divide| 无符号数除法 | |uint64.compare| 无符号比较相等返回 0大于返回正数小于返回负数 | |uint64.remainder| 无符号取模 | |uint64.parse| 字符串转无符号数 |2.4xlua.structclone克隆一个 C# 结构体struct。由于 struct 是值类型直接赋值可能共享引用尤其当结构体内部含引用类型字段时需要显式克隆时使用此函数local newStruct xlua.structclone(oldStruct)2.5xlua.private_accessible(class)使某个 C# 类型的私有字段、属性、方法在 Lua 侧可访问。当需要绕过 C# 的private修饰符进行测试或反射式访问时非常有用。底层实现在 StaticLuaCallbacks.csXLuaPrivateAccessible回调若找不到对应 C# 类型会返回 Lua 错误xlua.private_accessible, can not find c# type。2.6cast函数以指定接口访问对象适用于实现类型不可访问如 internal 类型的场景。假设calc对象实现了 C# 的PerformentTest.ICalc接口cast(calc, typeof(CS.PerformentTest.ICalc))调用后即可通过该接口成员操作对象。cast由ObjectTranslator.OpenLib中注册的castFunction实现出错时抛出c# exception in xlua.cast: ...见 StaticLuaCallbacks.cs。2.7 像表一样操作 C# 对象访问 C# 对象如同访问 Lua 表调用函数如同调用 Lua 函数甚至可以直接使用运算符调用 C# 的运算符重载。官方示例local v1 CS.UnityEngine.Vector3(1, 1, 1) local v2 CS.UnityEngine.Vector3(1, 1, 1) v1.x 100 v2.y 100 print(v1, v2) local v3 v1 v2 print(v1.x, v2.x) print(CS.UnityEngine.Vector3.one) print(CS.UnityEngine.Vector3.Distance(v1, v2))三、C# 与 Lua 类型映射3.1 基本数据类型映射| C# 类型 | Lua 类型 | | - | - | |sbyte,byte,short,ushort,int,uint,double,char,float|number| |decimal|userdata| |long,ulong|userdata/lua_IntegerLua 5.3 | |byte[]|string| |bool|boolean| |string|string|其中long/ulong在 Lua 5.3 下可映射到lua_Integer64 位有符号整数而ulong超出有符号范围的场景则走userdata配合上文uint64工具表使用。相关 push/take 逻辑在 ObjectTranslator.cs 与 ObjectCasters.cs 中有完整注册表。3.2 复杂数据类型映射| C# 类型 | Lua 类型 | | - | - | |LuaTable|table| |LuaFunction|function| | class 或 struct 实例 |userdata、table| | method、delegate |function|LuaTable若 C# 方法入参或 Lua 方法返回值指定为LuaTable类型则 Lua 侧必须是table若 C# 未指定类型Lua 中的table会被转换为LuaTable。LuaFunction同理指定LuaFunction时 Lua 侧必须是function未指定类型时 Lua 函数转换为LuaFunction。LuaUserData对应非 C# 托管对象的 Lua userdata。class 或 struct 实例C# 传入的类或结构体实例映射为 Lua userdata通过__index访问其成员。若 C# 指定了入参类型Lua 侧直接使用该类型实例的 userdata若该类型带默认构造函数Lua 中的table会被自动转换——转换规则为调用构造函数构造实例将 table 中与字段同名的键一一赋值给 C# 的对应 setter 成员。method 与 delegate成员方法与委托都对应 Lua 函数。C# 的普通参数与引用参数对应 Lua 函数参数C# 的返回值对应 Lua 的第一个返回值C# 的引用参数ref与out参数按顺序对应 Lua 的第 2 至第 N 个返回值。四、编译期宏Macros宏在 Unity 的 Player Settings → Scripting Define Symbols 中配置直接影响 xLua 源码的编译行为| 宏 | 作用 | | - | - | |HOTFIX_ENABLE| 启用热补丁hotfix功能。在源码 Hotfix.cs、DelegateBridge.cs 以及生成模板 LuaDelegateBridge.tpl.txt 中均以该宏作为功能开关。 | |NOT_GEN_WARNING| 存在反射未生成代码的调用路径时打印警告。 | |GEN_CODE_MINIMIZE| 以最小化代码段的方式生成代码。该宏在 Generator.cs 中控制生成代码的裁剪策略用于减小生成代码体积。 |五、实战组合示例与最佳实践结合上文 API给出一个同时覆盖 C# 侧与 Lua 侧完整链路的示例// 1. 创建全局唯一的 LuaEnv LuaEnv luaenv new LuaEnv(); // 2. 注册自定义 loader使 require 能加载自定义路径的脚本 luaenv.AddLoader((ref string filepath) { string path Assets/MyLua/ filepath.Replace(., /) .lua.txt; return System.IO.File.Exists(path) ? System.IO.File.ReadAllBytes(path) : null; }); // 3. 执行 Lua 代码并接收返回值 object[] ret luaenv.DoString( local t { name xlua, version 3 } return t ); LuaTable t ret[0] as LuaTable; Debug.Log(t.Getstring(name)); // 输出 xlua Debug.Log(t.GetInPathint(version)); // 输出 3 // 4. 加载函数并通过委托高频调用避免 LuaFunction 装箱开销 var func luaenv.LoadStringSystem.Funcint, int, int(return function(a, b) return a b end); Debug.Log(func(1, 2)); // 输出 3 // 5. 每帧 Tick 清理未手动释放的 LuaBase 对象 void Update() { luaenv.Tick(); } // 6. 不再使用时销毁 void OnDestroy() { luaenv.Dispose(); }关键实践要点单例优先全局只创建一个LuaEnv实例避免多虚拟机带来的内存与同步开销。周期性 GC在Update中调用Tick()让未手动释放的LuaTable/LuaFunction被及时回收。委托替代 LuaFunction高频调用路径使用table.GetDelegate或LoadStringDelegate并把委托类型加入 custom_generate.md 所述的生成代码列表规避装箱/拆箱。路径读取用 GetInPath/SetInPath嵌套表访问用GetInPathT替代多次Get减少跨语言调用次数。类型映射牢记于心byte[]↔ Luastring、long/ulong在 Lua 5.3 下的映射差异以及ref/out参数出现在 Lua 侧返回值序列中的规则是排查跨语言参数错位问题的关键。如需进一步了解热补丁、生成代码配置与 FAQ可继续阅读仓库中的 hotfix.md、configure.md 与 faq.md。【免费下载链接】xLuaxLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc.项目地址: https://gitcode.com/gh_mirrors/xl/xLua创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表