跳到主要内容

元表模型

:::tip 谁该读本文 需要理解 obj:Member 底层如何查表、为何报错「member not found」的开发者。 日常用法见 字段与属性方法重载。 :::

Lua 通过 __index / __newindex 访问 C# 静态与实例成员。ZLua 采用 三表分派 + strict miss:未注册成员直接 luaL_error回退到 C# 反射。

三表分派

每个静态域或实例域各维护三张表:

读 (__index)写 (__newindex)
methodTable方法、dispatch、别名、Event 表
fieldGetterTable字段、无参 property 读
fieldSetterTable字段、无参 property 写

:::note 写路径 __newindex 查 methodTable;赋值给不存在键直接报错。 :::

查表时序(实例读)

strict miss 示例

以下均 直接报错,不会尝试反射查找 private 或父类未注册成员:

local demo = CSharp.AC.Demo()
demo.nonExistentField = 1 -- error: member not found
demo:PrivateMethod() -- error(private 未注册)

与 dispatch 的区别: 多重重载时 demo:Run(x) 在 methodTable 上可能是 单个 dispatch closure,内部分派到具体桥接,仍算 methodTable 命中。

方法重载在三表中的形态

情况methodTable["Run"]
单一 public 重载直接桥接 closure
多个重载dispatch closure(运行时分派)
[LuaAlias("run_i32")]额外键 run_i32 → 单桥接 closure

签名字符串 不是 methodTable 的 Lua 键;禁止 demo[sig](demo, ...)

平台实现

运行时__index / __newindex 实现
Mono (Editor)Lua function,C# 侧查三表
Il2Cpp (Player)C closure DispatchIndex / DispatchNewIndex

Lua 可见语义一致;Il2Cpp 可内联字段 offset 读,仍走同一分派顺序。

何时读规范

问题文档
dispatch 算法方法重载规范
Property / Event 注册类型系统规范
完整 obj_indexer 规格元表索引规范
远期 VM 快路径VM 索引规范

相关文档