跳到主要内容

枚举编组

规范性: C# enum 在 Lua 与 C# 之间的默认编组规则。
相关: 类型表常量字段 → ../02-TYPE-SYSTEM.md §枚举;boxed 形态 → ../05-LIB.md box/unboxref enum → 03-BYREF.md[LuaMarshalAs]02-MARSHAL-AS.md

平台原则: Mono 与 Il2Cpp 的 Lua 可见语义一致;枚举默认 推送 userdata,而按 integer / number 编组。


1. 设计要点

枚举在 C# 中为 值类型,底层为单一整型字段。Lua 侧:

场景形态
默认传参integer(Lua 5.4+ 优先)或 number
boxed 实例ByObjUserData 经显式 zlua.box
类型表常量integer / number 字段( userdata)

枚举类型表 SMT.__call不可 像 struct 那样 EnumType(...) 构造 ByVal userdata。


2. 默认规则(C# ↔ Lua)

未标注 [LuaMarshalAs] 时:

方向默认形态说明
C# → Luainteger(优先)或 number推送枚举的 底层整数值 推送 userdata
Lua → C#integer / number接受整型 Lua 值,按目标枚举 底层类型 转换并 Enum.ToObject / 等价路径
Lua → C#(备选)ByObjUserData(boxed enum)从 boxed 对象解包 underlying 整型

不接受(除非 [LuaMarshalAs] 另行规定):默认编组为 string(枚举名)、boolean、或普通 table


3. 底层类型与范围

Codegen / 反射须读取枚举 underlying typeSystem.Int32System.Byte 等):

底层类型Push 优先Pop 接受
sbyteulonginteger / numberinteger / number(须为整型)
非整型底层(罕见)numbernumber

Pop 时校验 Lua 整型值是否落在底层类型可表示范围内;越界 → luaL_error

整型基元规则(integer vs number)见 01-OVERVIEW.md §1.1。


4. 与类型表常量字段的关系

Bind 期将枚举 public static literal 写入类型表 E

local Color = CSharp.AC['MyGame.Color']
assert(Color.Red == 0) -- integer / number,非 userdata

访问路径:CSharp.AC['MyGame.Color'].Red

下列写法作为 enum 形参 时等价(默认 marshal):

local e = Color.Red
foo(e)
foo(Color.Red)
foo(1) -- 裸整型,须能转换为该 enum

详见 ../02-TYPE-SYSTEM.md §枚举类型。


5. Boxed 形态(非默认,zlua.box

当脚本需要 boxed enum 实例object 形参、Array.SetValue、长生命周期 ByObj 等):

local Color = CSharp.AC['MyGame.Color']
local boxed = zlua.box(Color, Color.Red)
-- 或
local boxed2 = zlua.box(Color, 2)
说明
第一参数枚举类型表、zlua.typeof(E) 或等价 typeArg
第二参数integer / number(整型);或同枚举常量字段值
返回值ByObjUserData(boxed 对象;不是 struct ByVal payload)
拆箱zlua.unbox(boxed) → underlying integer

作为 enum 形参 传入 C# 时,ByObjUserData 与 integer/number 均接受(§2)。

zlua.box 产物用于 ref Color 为 ByObjUserData,走 03-BYREF.md 引用/临时槽 路径(非 ByValUserData payload 直传)。


6. ref / out / in enum 形参

03-BYREF.md

Lua 实参行为
OpaqueValue(类型兼容)传 handle 地址
ByValUserData(若存在且类型 == enum)传 payload 地址
integer / number拷贝进栈临时变量,传临时地址;Lua 裸值 不变
zlua.box 产物(ByObj)指针写入临时槽,传临时地址

C#→Lua:ref enum 默认 OpaqueValue;见 04-OPAQUE.md


7. [LuaMarshalAs] 扩展

标注enum by-val
Default§2 规则
UserData非法(by-val enum 不可强制 userdata);回退 Default,Editor 打错误日志
OpaqueValueby-val 合法(C#→Lua;通常无实质必要);ref/out/in 时 C#→Lua 默认已是 OpaqueValue
Table / UnpackedValues非法(仅 struct / class / interface)

boxed 形态仍须 zlua.box enum SMT.__call

非法标注行为见 02-MARSHAL-AS.md §非法标注。


8. 与 struct / class 的差异(摘要)

enumstructclass
默认跨边界integer/numberByValUserData / StructUserDataClassUserData
类型表 __call.ctor.ctor
boxed / 实例构造zlua.boxType(...) / _defaultType(...)
类型表常量integer/number通常无静态成员
ref 写回Opaque / 匹配 ByValUserDataByValUserData / Opaque;其它进临时槽06-CLASS.md

9. Mono / Il2Cpp 一致性

要求
默认 Push / Popinteger/number ↔ 底层整型
类型表常量integer/number
boxedzlua.box → ByObjUserData
范围校验一致
错误消息一致或等价

10. 相关文档

文档内容
01-OVERVIEW.md默认矩阵、integer/number
03-BYREF.mdref / out / in
04-OPAQUE.mdC#→Lua byref
05-STRUCT.mdByVal / ByObj 与 box 对比
../02-TYPE-SYSTEM.md枚举类型表结构
../05-LIB.mdboxunbox