跳到主要内容

指针与不支持类型

规范性: 非托管指针、函数指针、以及 v1 默认不支持或受限的 CLR 形态之编组规则。
相关: 默认矩阵 → 01-OVERVIEW.mdIntPtr 整型规则 → 01-OVERVIEW.md;OpaqueValue 对比 → 04-OPAQUE.md;Delegate 对比 → 09-FUNCTION.mdref struct05-STRUCT.md../05-LIB.md

平台原则: Mono 与 Il2Cpp 的 Lua 可见语义一致


1. 与 IntPtr / UIntPtr 的区分

§1 总览中 IntPtr / UIntPtr / nint / nuint整型数值 编组(ToInt64 / new IntPtr),不是 本节 Pointer。

类型Lua 默认形态脚本可当作整数运算
IntPtr / UIntPtr / nint / nuintinteger / number可以(按数值)
T* / void* 等非托管指针Pointer(lightuserdata)不可以(仅透传)
函数指针 delegate*<…>Pointer(lightuserdata)不可以(仅透传)

2. 非托管指针(T*void* 等)

范围: CLR 中 Type.IsPointer == true 且元素为 非托管 类型的指针,例如 int*byte*void*MyStruct*MyStruct 为 unmanaged struct)。

不包含 IntPtr / UIntPtr(见 §1)。

2.1 默认编组

方向默认形态说明
C# → LuaPointerlightuserdataPush 指针 地址值uintptr_t / 平台指针宽度); metatable
Lua → C#PointerlightuserdataPop 时须为 Pointer 形态;按声明指针类型还原

2.2 Lua 侧能力(刻意受限)

允许禁止
作为实参 原样传递 给下一个 C# 调用(同步链内透传)解引用、读写指向内存
nil 区分(非 null 指针才有 Pointer): / . 成员访问、算术、#pairs
写入全局 / 表 / upvalue 后在 异步跨 pcall 使用(地址可能失效)

设计理由: Lua 无法安全表达 C# 非托管指针的生命周期与别名;仅支持 不透明令牌式透传,供 native / 底层 API 衔接。

2.3 [LuaMarshalAs]

非托管指针允许 DefaultOpaqueValue(仅 C#→Lua)。UserDataTable 等仍 非法(见 02-MARSHAL-AS.md)。OpaqueValue 与默认 Pointer lightuserdata 不同:走 Opaque 槽与 get_opaquevalue / set_opaquevalue 生命周期规则。


3. 函数指针(function pointer)

范围: CLR 中 Type.IsFunctionPointer == true 的类型,例如 C# 9+ 的 delegate*<int, int>delegate*<void>

3.1 默认编组

方向默认形态说明
C# → LuaPointerlightuserdataPush 函数入口 地址 metatable
Lua → C#PointerlightuserdataPop 还原为对应 function pointer 类型

3.2 Lua 侧能力

与 §2 相同——仅透传,不能从 Lua 侧 调用 该地址。

3.3 [LuaMarshalAs]

与 §2.3 相同:允许 DefaultOpaqueValue(仅 C#→Lua)。

3.4 与 Delegate 对比

类型Lua 默认形态Lua 侧可调用
Action / Func<…> 等 DelegateDelegateUserData 或 Lua function可以(见 09-FUNCTION.md
delegate*<…> 函数指针Pointer(lightuserdata)不可以

4. System.TypedReference

TypedReference OpaqueValue 形态在 C# ↔ Lua 之间传递;默认即为 OpaqueValue,无需再标 [LuaMarshalAs(OpaqueValue)]。其它 marshal 形态(UserData / Table / integer 等)均不支持

方向规则
C# → Lua默认 Push OpaqueValue04-OPAQUE.md);脚本经 get_opaquevalue / set_opaquevalue 读写
Lua → C# 接受兼容的 OpaqueValue handle(类型校验后绑定地址);其它 Lua 形态 → 错误
其它 [LuaMarshalAs]非法(回退或绑定期拒绝,见 02-MARSHAL-AS.md

原因: TypedReference 绑定受控栈上的类型化槽位,无法稳定映射为普通 Lua 值或 userdata;OpaqueValue 仅暴露当前调用期内的槽地址,与其语义匹配。


5. 其他不支持或受限类型

下列类型在 01-OVERVIEW.md 总览中已简要列出;此处集中说明。

5.1 decimal

方向规则
默认暂不支持
[OpaqueValue](C#→Lua)合法
Pop/Push(Default)未纳入 v1 默认路径

5.2 ref structSpan<T>ReadOnlySpan<T> 等)

方向规则
by-val 形参不能 作为普通默认 marshal
受控路径ref StructUserData / 04-OPAQUE.md OpaqueValue 等

详见 05-STRUCT.md../05-LIB.md

5.3 Nullable<T>

方向规则
有值T 的 marshal
nullnil
T 为值类型Pop 接受 nil

01-OVERVIEW.md../02-TYPE-SYSTEM.md §Nullable。

5.4 dynamic

编译期按 object 处理;无独立 Lua 形态。

5.5 开放泛型形参

void M<T>(T x)T 未实例化:由 调用时类型实参 决定 marshal;见 ../02-TYPE-SYSTEM.md


6. 注册 / 暴露阶段应拒绝的签名

以下属于 签名非法(非 marshal 规则细节):

条件行为
ref struct by-val 形参组合拒绝
无法解析的 byref 修饰符 组合拒绝

允许: [LuaInvoke]delegate bridge 上的 ref/out/in(C#→Lua 见 04-OPAQUE.md;Lua→C# 见 03-BYREF.md)。


7. Pointer Pop 细则

规则
接受形态 Pointer lightuserdata
接受integer / number、full userdata、OpaqueValue handle 的隐式互转
null 指针C#→Lua:按实现 Push Pointer 或 nil(须两平台一致);Lua→C#:nil 是否对应 null 指针以实现文档为准
错误类型不匹配 → luaL_error / 等价异常

8. 三种 lightuserdata 对比

种类用途metatable脚本读写
Pointer(§2、§3)非托管指针 / 函数指针透传不可解引用
OpaqueValue04-OPAQUE.mdC# 栈帧参数槽 handleget_opaquevalue / set_opaquevalue
(非 lightuserdata) ClassUserData 等托管对象 IMT: / . 成员访问

9. Mono / Il2Cpp 一致性

要求
Pointer / function pointer Pushlightuserdata,地址宽度 = 平台指针
Pointer Pop仅接受 Pointer;不与 integer / full userdata 隐式互转
TypedReference OpaqueValue(默认即此);语义一致
decimal / ref struct by-val一致的不支持或受限行为
错误消息一致或等价

10. 相关文档

文档内容
01-OVERVIEW.md默认矩阵、IntPtr
02-MARSHAL-AS.md指针类型合法标注集合
04-OPAQUE.mdOpaqueValue vs Pointer
09-FUNCTION.mdDelegate vs 函数指针
05-STRUCT.mdref struct
../02-TYPE-SYSTEM.mdNullable、特殊类型族