Class / Interface 编组
规范性: 引用类型(
class、interface、string、数组实例、delegate 实例等)在 Lua 与 C# 之间的默认编组规则。
相关: 类型表与成员访问 →../02-TYPE-SYSTEM.md;ref/out/in总览 →03-BYREF.md;[LuaMarshalAs]→02-MARSHAL-AS.md;zlua.cast→../05-LIB.md。
平台原则: Mono 与 Il2Cpp 的 Lua 可见语义一致;class 实例默认 GCHandle + full userdata(Il2Cpp:ObjectRegistry + Il2CppObject*)。
1. 默认编组(概要)
未标注 [LuaMarshalAs] 时,引用类型遵循 01-OVERVIEW.md 总览矩阵;本节补充 class / interface 特有语义。
| 方向 | Lua 形态 | 说明 |
|---|---|---|
| C# → Lua | ClassUserData(ByObj full userdata) | 引用身份;IMT 门面 = 声明类型(见 §2) |
| Lua → C# | ClassUserData 或 nil | 校验可赋值给目标 声明类型;nil ↔ null |
string | Lua string 或 nil | 仅当声明类型为 string;声明为 object 时仍为 Object userdata |
interface | 同 class | 门面 = 接口声明类型(非实现类);见 §2、§4 |
| 数组 | ByObjUserData | 见 07-ARRAY.md |
| Delegate | function 或 DelegateUserData | 见 09-FUNCTION.md |
UserData 形态: ClassUserData 为 lua_newuserdata + 实例元表 IMT 的 full userdata;脚本侧经 : / . 访问成员。与 04-OPAQUE.md 的 OpaqueValue(lightuserdata、无 metatable)及 10-POINTER.md 的 Pointer 不同。
字段、方法、静态成员访问细节见 ../02-TYPE-SYSTEM.md 与 ../metatable/。
2. 声明类型门面(View / 与实际类型)
对所有 引用类型 形参、返回值、字段/属性(class / interface / object / 数组 / delegate 等),编组层区分 Identity 与 View:
| 概念 | 含义 |
|---|---|
| Identity | userdata 载荷持有的托管对象引用(运行时 实际实例) |
| View / 门面 | userdata 挂接的 IMT 与成员可见性;唯一来源 = 本次编组的声明类型 |
2.1 规则
- C# → Lua:始终按 声明类型 选择默认 marshal 形态与 ByObj IMT;不因运行时实际类型不同而改挂更具体类型的 mt,也 不 因此改走
string等特殊编组(例如object形参上的string实例仍为 Object userdata,不是 Lua string)。 - 值类型:无继承门面问题;仍按
05-STRUCT.md等规则。 - 虚方法:成员查找使用 声明类型 上的
MethodInfo;调用时对真实this做 虚表派发(override仍落到实现类)。 - 非虚 /
new隐藏:走声明类型槽位(经Base门面调用new隐藏的Bar得到Base.Bar)。 - Downcast:仅
zlua.cast(IsAssignableFrom(targetType, obj.klass));返回 新 userdata(同 identity、新门面)。 - 对象缓存:键为
(identity, viewType);同一实例可有多个视图 userdata。
2.2 示例
Base CreateChild() => new Child();
local o = ObjectFactory.CreateChild() -- 门面 Base:不可见 Child.y;new Bar → Base.Bar
local c = zlua.cast(o, Child) -- 门面 Child(须 IsAssignableFrom)
虚方法经 Base 门面查找 MethodInfo,再对真实实例 虚派发。
2.3 object 形参
| 项 | 规则 |
|---|---|
| Push | ClassUserData,门面为 System.Object |
| Pop | 接受 boolean / number / string / userdata |
| 运行时类型 | 不 按运行时类型改写编组(运行时 string 仍为 Object userdata) |
Nullable<T> 其中 T 为引用类型时,null ↔ nil;有值时同 T 的 class 规则。见 01-OVERVIEW.md。
3. Table / UnpackedValues(class / interface)
class 与 interface 默认 均为 ByObjUserData(ClassUserData),不 默认接受 Lua table 或多栈参数整对象组装。
须显式标注 [LuaMarshalAs] 的 Table 或 UnpackedValues,并配置 FieldOrPropertyNames(string[],field/property 可混合):
| 形态 | Lua 侧 | 说明 |
|---|---|---|
Table | 单个 table ↔ 名单成员 | 键为成员名;可选 ? 后缀见 02-MARSHAL-AS.md |
UnpackedValues | 连续 N 个栈槽 ↔ 名单成员 | 顺序与名单一致 |
Pop 时须能构造 实现该接口的实例 或 class 实例(如无参 ctor + property setter,或实现层规定的工厂);名单内成员须为接口 / 类型上可访问的 public field/property;引用类型成员 按该成员类型的 §1 默认规则递归 Pop/Push。
interface 与 class / struct 一样,允许 Table / UnpackedValues(合法集合见 02-MARSHAL-AS.md)。
4. Interface 编组
| 项 | 规则 |
|---|---|
| 默认 C# ↔ Lua | ByObjUserData(ClassUserData);门面 = 接口声明类型(非实现类) |
nil | ↔ null |
[LuaMarshalAs] | 可与 class 相同覆盖:UserData、OpaqueValue、Table、UnpackedValues(见 02-MARSHAL-AS.md) |
| 成员访问(默认 userdata) | 仅接口上可见成员 + 继承的接口成员;实现类独有成员不可见 |
5. ref / out / in 引用类型形参(Lua → C#)
总览见 03-BYREF.md。引用类型(含 string)要点:
| Lua 实参 | 行为 |
|---|---|
| OpaqueValue(与 A 类型兼容) | 传 handle 地址(可写回原槽) |
ByObjUserData / Lua string(仅当 A 为 string)/ nil / 其它可 Pop 形态 | 取得托管指针(或 null)→ 写入 栈临时变量 → 传临时地址 |
5.1 写回:临时槽 ⇒ 无 rebind
| C# 侧操作 | Lua 侧(临时槽路径) |
|---|---|
refParam = otherObject(重新绑定) | 不可见 |
| 对 可变对象 原地修改 | 可见(同一托管对象) |
ref string 赋新字符串 | 不可见(等同 rebind) |
local s = "hello"
CS.Demo.ChangeString(s) -- void ChangeString(ref string s) { s = "world"; }
-- s 仍为 "hello"
local sb = StringBuilder("hi")
CS.Demo.Append(sb, "!") -- 共享引用,内容可变
5.2 C# → Lua
ref/out/in 默认 Push OpaqueValue,见 04-OPAQUE.md。
6. string 编组补充
| 声明类型 | C# → Lua | Lua → C# |
|---|---|---|
string | Lua string | Lua string 或 nil |
object(运行时 string) | Object userdata(门面 System.Object) | 按 object Pop 规则 |
[LuaMarshalAs(UserData)] on string | ByObjUserData(托管 System.String 对象) | 强制 userdata 路径 |
[LuaMarshalAs(Bytes)] 用于 byte[] ↔ Lua string,不是 System.String;见 07-ARRAY.md。
7. Mono / Il2Cpp 一致性
| 项 | 要求 |
|---|---|
| 默认 Push / Pop | ClassUserData;nil ↔ null |
门面 (identity, viewType) | 两平台一致 |
zlua.cast | 同 identity、新 view |
| C#→Lua byref | OpaqueValue(04-OPAQUE.md) |
| 错误消息 | 一致或等价 |
8. 相关文档
| 文档 | 内容 |
|---|---|
01-OVERVIEW.md | 默认编组矩阵 |
03-BYREF.md | ref / in / out 总规则 |
04-OPAQUE.md | C#→Lua byref 默认 OpaqueValue |
07-ARRAY.md | 数组 ByObjUserData |
09-FUNCTION.md | Delegate 编组 |
../02-TYPE-SYSTEM.md | 类型表、IMT、成员访问 |
../05-LIB.md | cast、box |