跳到主要内容

特性与用法对比(xLua / toLua / SLua / ZLua)

性质: 选型材料,非 ZLua 行为规范。
ZLua 状态: Mono(Editor)与 Il2Cpp(Player)均已完成(见 impl/MONO.md)。


1. 总览对照

维度xLuatoLua / tolua#SLuaZLua
Lua 引擎独立 libxlua(P/Invoke)内嵌或绑定原生 lua内嵌 lua链入 libil2cpp(Player)/ 内嵌(Editor)
类型入口CS.Namespace.Type导出全局 / 包装类类似 toLua + 配置CSharp[assembly]['Full.Name'] 懒加载
Lua→C# 桥生成 C# Wrap + LuaDLL生成 *.Wrap.cs自动绑定 + 导出C++ MethodBridge(Il2Cpp)/ Expression Emit(Mono)
C#→LuaLuaEnv + LuaFunction + 多次 LuaDLLLuaState / LuaFunctionLuaSvr / LuaFunction[LuaInvoke] InternalCall + C++ 模板
白名单 / 导出[LuaCallCSharp] / [CSharpCallLua] + Generate手动列表 / Binder导出配置 / Attribute LuaCall 白名单;按 public + 懒 Bind
Editor vs Player基本一致(均走 libxlua + Wrap)基本一致基本一致双轨:Mono Emit vs Il2Cpp native(语义须一致)
侵入 Unity插件包 + native插件包插件包fork libil2cpp(Player)
Event专用支持视版本视版本;用 add_ / remove_ 普通方法
文档 / 社区弱(停更风险)建设中

2. 类型访问

2.1 语法对照(同一类型 MyGame.Demo

方案典型写法
xLuaCS.MyGame.Demo
toLuaDemo(导出后全局)或 UnityEngine.GameObject
SLuaUnityEngine.GameObject(自动导出命名空间)
ZLuaCSharp['Assembly-CSharp']['MyGame.Demo']CSharp.AC['MyGame.Demo']

ZLua 规则要点:

  • 命名空间 的类型必须用 括号键 整段 typeFullName,禁止 CSharp.AC.MyGame.Demo. 不是表路径)。
  • 嵌套类型用 +CSharp.AC['Outer+Inner']
  • 程序集名为简单名:Assembly-CSharpmscorlib

详见 spec/02-TYPE-SYSTEM.md §2。

2.2 懒加载 vs 预导出

方案模型包体 / 链接影响
xLuaGenerate 白名单类型 → Wrap 进包未导出类型不可调;可控制体积
toLua / SLua导出列表决定 Wrap 数量导出越多,生成代码越大
ZLua首次访问 CSharp[asm][type]EnsureBinding运行时绑定 + Il2Cpp stub 表;未访问类型不占桥接表项(但链接仍保留元数据)

2.3 泛型与数组

能力xLuatoLuaSLuaZLua
闭泛型CS.System.Collections.Generic.List(CS.System.Int32)需预导出或反射配置导出zlua.make_generic_type(base, ...)
数组类型导出或反射导出导出zlua.make_szarray_type / make_mdarray_type
运行时构造数组支持(视导出)有限有限zlua.new_szarray_by_element_type

3. 成员调用(Lua→C#)

3.1 静态 / 实例

统一示例: 静态 Demo.Add(1, 2),实例 obj:GetX()

方案静态实例
xLuaCS.Demo.Add(1, 2)obj:GetX()
toLuaDemo.Add(1, 2)obj:GetX()
SLua同 toLua同 toLua
ZLuaDemo.Add(1, 2)Demo 为类型表)obj:GetX()

ZLua 静/实例 分离三表(method / fieldGetter / fieldSetter);继承成员在 Bind 期扁平化,无运行时沿继承链查找。

3.2 字段与属性

方案读字段写只读属性
xLua常经 Wrap / propertyWrap 报错
toLua / SLuaWrap 或 getter同左
ZLuaobj.x → fieldGetter 表;Il2Cpp 可走 offset 直读__newindex miss → error

3.3 方法重载

方案策略
xLua生成 Wrap 内 overload 分派
toLua / SLuaWrap 内分派或单一签名
ZLuaBind 期注册;默认 最佳匹配[LuaAlias] / register_method 显式绑定(见 spec/04-METHOD-OVERLOAD.md

ZLua 特有能力:

-- Bind 期 [LuaAlias("foo_str")] 单候选 direct closure
obj:foo_str("a")

-- 或运行时挂新名(须尚未占用)
local run = demo.run_i32
zlua.register_method("run_hot", run)
demo:run_hot(1)

3.4 __index miss 语义

方案不存在成员
xLua通常 nil 或 error(视 Wrap)
toLua / SLua多 error
ZLuanil(读);写未知键 error

4. C#→Lua

4.1 入口对照

方案C# 调 Lua 函数Lua 函数 → C# delegate
xLuaLuaEnv.DoString / LuaFunction.Call / [CSharpCallLua]LuaFunction / Delegate
toLuaLuaState.DoFile / LuaFunctionLuaFunction.ToDelegate
SLuaLuaSvr + LuaFunctionSLua delegate 绑定
ZLua[LuaInvoke("module", "func")] static extern方法形参 隐式 marshalAction/Func 等)

ZLua [LuaInvoke] 示例:

[LuaInvoke("game", "OnTick")]
public static extern void OnTick(float dt);
  • Editor:Weaver + Emit 桥( object[] legacy)。
  • Player:InternalCall → C++ LuaInvokeRuntime::Call,构建期解析 moduleRef/funcRef

4.2 模块加载

方案加载
xLuarequire + 自定义 loader
toLua / SLua自定义 loader
ZLuaLuaAppDomain.Initialize(moduleLoader);与 require 集成(见 spec/01-HOST-API.md

5. 值类型、ref、struct

主题xLuatoLua / SLuaZLua
struct 传参多装箱或 table视 WrapByVal userdata 拷贝 / ByObj boxed
struct 返回值常分配同左ByVal payload 或 boxed(见 spec/marshal/05-STRUCT.md
ref/out Lua→C#多返回值或 table多返回值StructUserData(Type(...) / C# 推送)或拷贝语义
C#→Lua ref/out视版本有限OpaqueValue(仅当次调用帧有效)
enumnumber / 导出类型导出integer 默认;可 ByObj boxed
zlua.cast声明类型门面转换

Opaque 边界(ZLua 特有,迁移易踩坑):

  • C# [LuaInvoke]ref int 推到 Lua 侧是 OpaqueValue,不是 integer;须 zlua.get_opaquevalue / set_opaquevalue
  • Opaque 不可跨 pcall 持久化

6. 热更、代码生成与裁剪

维度xLuatoLua / SLuaZLua
热更实践大量现成方案(字节码、资源)项目自建需自建;ZLua 不绑定特定热更框架
代码生成XLua Generate All导出 WrapIl2Cpp:Codegen C++ stub + Weaver [LuaInvoke];Mono:Emit(不进 Player 包)
反射兜底有(慢路径)部分禁止热路径静默 Method.Invoke;无法 Emit 则 绑定期失败
链接 / 裁剪白名单控制 Wrap导出列表public 类型可懒 Bind;Il2Cpp ReducedType 控制 stub 体积(见 BRIDGE.md
Unity 升级升 xLua 包为主风险高merge libil2cpp 补丁(工程债)

7. Editor / Player 一致性

方案双端
xLua / toLua / SLua通常同一套 lib + Wrap,Editor ≈ Player
ZLua必须 Mono 与 Il2Cpp Lua 可见语义一致;实现不同(Emit vs C++ stub)

测试要求: 同一套用例在 Editor 与 Il2Cpp Player 各跑一遍;任一失败即失败(见 guides/TESTING.md)。

索引器 Property / 开放泛型等:见 兼容性矩阵spec;双端语义一致,有限制项两端相同。


8. 侵入性与维护

浅 ←────────────────────────────────────────→ 深(Il2Cpp 侵入)

纯 C# 反射桥
xLua / toLua / SLua(插件 + native / Wrap)
★ ZLua Player 目标(嵌入 libil2cpp)
HybridCLR 级 VM 改造(ZLua 不做)
层级xLuatoLua / SLuaZLua
修改 libil2cpp(Player)
独立 nativelibxlua可选否(与 il2cpp 同二进制)
GC 钩子一般无一般无non-blittable struct 等可能 hook push_other_roots
维护焦点包版本停更风险Unity 版本 + zlua 补丁 merge

9. 配置与白名单

方案机制
xLua[LuaCallCSharp][CSharpCallLua][ReflectionUse]、Generate 配置
toLua自定义 CustomSettings.cs 导出列表
SLua[CustomLuaClass]、导出 XML / 代码
ZLua LuaCall 式白名单;public 成员可 Bind;[LuaMarshalAs] / [LuaAlias] 影响编组与别名;Weaver 处理 [LuaInvoke]

迁移含义: 从 xLua 迁出时需 删除 Generate 配置,改为确认程序集内 public API 是否应暴露给 Lua;敏感 API 应改 非 public 而非依赖导出列表。


10. 不支持或弱支持项(迁移检查清单)

xLuatoLua / SLuaZLua
C# Event 语法糖视版本add_Xxx / remove_Xxx
运行时继承查找(Bind 期扁平化)
CS. 全局N/ACSharp
热路径反射 Invoke兜底部分显式错误
跨帧 OpaqueN/AN/A禁止
任意 Lua function 存成永久 delegate 无 GC 顾虑需注意 translator需注意须理解 spec/10-LIFETIME.md

11. 同一示例四列对照

需求: 调用 MyGame.Demo.Add(1, 2),创建实例并读字段 x

-- xLua
local Demo = CS.MyGame.Demo
local sum = Demo.Add(1, 2)
local obj = Demo()
local x = obj.x

-- toLua(已导出 Demo 到全局)
local sum = Demo.Add(1, 2)
local obj = Demo.New()
local x = obj.x

-- SLua
local Demo = MyGame.Demo
local sum = Demo.Add(1, 2)
local obj = Demo()
local x = obj.x

-- ZLua
local Demo = CSharp['Assembly-CSharp']['MyGame.Demo']
local sum = Demo.Add(1, 2)
local obj = Demo()
local x = obj.x

12. 选型摘要

更适合方案
立刻上线、要少踩坑、团队已有 xLua 资产xLua
老项目 toLua/SLua 已稳定、改动面小维持原方案(迁移 ZLua 成本高)
Player 性能边界是瓶颈、愿维护 libil2cpp、要 C# 语义一致ZLua
不愿改引擎层、不需极致互调性能xLua 优于 ZLua

迁移步骤见 guides/migration/


相关文档

文档内容
PERFORMANCE.md性能对比
GC.mdGC 对比
spec/02-TYPE-SYSTEM.mdZLua 类型系统规范