跳到主要内容

LuaMarshalAs

当默认 Marshal(见 速查表)不够用时,用 [LuaMarshalAs]XML 覆盖。权威全文:02-MARSHAL-AS。0GC 专题见 0GC Marshal

何时需要

  • byte[] ↔ Lua string(Bytes
  • struct 用 多栈槽单 table 组装(UnpackedValues / Table
  • C#→Lua 强制 Opaqueref/out/in 默认已是
  • 巨大 string 不想拷成 Lua string(UserData → ByObj)
  • 预编译 DLL 无法改源码 → Settings 挂 XML

可标注:参数 / 返回值 / 字段 / 属性 / 类型(class、struct)不可标在方法上;不可标在仍含未绑定泛型形参的槽位。

常用 LuaMarshalType

适用(摘要)用途
Default全部不覆盖
Bytesbyte[] / stringoctet ↔ Lua string
OpaqueValue仅 C#→LuaPush Opaque;byref 默认已是
UnpackedValuesstruct不含 Nullable / class)多连续栈槽 ↔ Members
Tablestruct / Nullable<struct>(不含 class)单 table ↔ Members
UserData实质几乎只对 string强制 ByObjUserData

Table / UnpackedValues 必须配置 Members;名字以 ? 结尾表示 Table 侧缺键不赋值。

用例

Bytes

public void Send([LuaMarshalAs(LuaMarshalType.Bytes)] byte[] payload) { }
host:Send("\0\1\2\3") -- Lua string,原始字节语义

UnpackedValues(struct 多槽)

形参占用 N 个 Lua 栈位(N = Members 长度),热路径常用:

using ZLua;

public struct Vec2 { public float X, Y; }

public class Mover
{
public void Move(
[LuaMarshalAs(LuaMarshalType.UnpackedValues, Members = new[] { "X", "Y" })]
Vec2 delta) { /* ... */ }

[return: LuaMarshalAs(LuaMarshalType.UnpackedValues, Members = new[] { "X", "Y" })]
public Vec2 Origin() => new Vec2 { X = 0, Y = 0 };
}
local m = CSharp.AC.Mover()
m:Move(3.0, 4.0) -- 两槽 → X, Y

local x, y = m:Origin() -- C#→Lua 展开多返回值
print(x, y)

类型级标注(该类型所有默认 Marshal 槽位):

[LuaMarshalAs(LuaMarshalType.UnpackedValues, Members = new[] { "x", "y", "z" })]
public struct Vector3 { public float x, y, z; }

Table(struct / Nullable<struct>)

占用 1 个栈槽;可读性更好,但 Lua 侧有 table 分配:

public struct Packet
{
public int Id;
public float X, Y;
public string Tag; // 可选键见 Members "?"
}

public void Submit(
[LuaMarshalAs(LuaMarshalType.Table, Members = new[] { "Id", "X", "Y", "Tag?" })]
Packet p) { }

public void TryPlace(
[LuaMarshalAs(LuaMarshalType.Table, Members = new[] { "X", "Y" })]
Vector2? pos) { }
host:Submit({ Id = 1, X = 2, Y = 3 }) -- Tag 可省略
host:TryPlace({ X = 1, Y = 2 })
host:TryPlace(nil) -- Nullable 无值

XML 等价(预编译程序集):

<Type fullName="UnityEngine.Vector3">
<MarshalAs type="Table" members="x,y,z" />
</Type>
<Type fullName="UnityEngine.Transform">
<Method name="LookAt" signature="(UnityEngine.Vector3)">
<Param index="0">
<MarshalAs type="UnpackedValues" members="x,y,z" />
</Param>
</Method>
</Type>

OpaqueValue

// by-val 强制 Opaque(C#→Lua);ref/out/in 无需再标
public void PushPos([LuaMarshalAs(LuaMarshalType.OpaqueValue)] Vector3 p) { }

Lua 侧用 zlua.get_opaquevalue / set_opaquevalue不可跨帧保存。见 0GC Marshalref/out/in

UserData(巨大 string)

默认 string ↔ Lua string(会拷贝)。标 UserData 后走 ByObjUserData(托管 System.String),避免生成巨大 Lua 字符串:

public void HandleHuge(
[LuaMarshalAs(LuaMarshalType.UserData)] string payload) { }

仍会产生 Lua userdata GC;并不常见,见 0GC Marshal

params 陷阱

默认 不能 Sum(1,2,3) 多槽隐式收集;须传 单个 table / 数组 userdata / nil

优先级(口诀)

槽位 Attribute → XML → 类型级 Attribute → 内置默认;Attribute 胜 XML。

非法类型/方向 → 回退 Default + Editor 日志;缺 Members 等 → 绑定期 / Generate 失败

简单 XML 规则

Settings MarshalAs Xml Paths;Mono 运行时解析;Il2Cpp 在 Generate 写入表,Player 不读 XML

要点:Paramindex(0-based,不含 this)typeOpaqueValue(勿用废弃名);别名走独立 luaAliasXmlPaths。完整 schema 见 规范 §9

学习路径

上一篇ref / in / out
下一篇0GC Marshal

相关文档