跳到主要内容
文档站副本

本页为语义契约的发布副本;请在上游 ZTSTest/Docs/spec 修改后执行 npm run sync-spec。(源:marshal\02-MARSHAL-AS.md

[TsMarshalAs]TsMarshalType

规范性: 参数、返回值、字段、属性及类型(class / struct)上的 Marshal 覆盖规则。 默认矩阵: 未覆盖时见 01-OVERVIEW.md源码: ZTS.Common 中的 TsMarshalAsAttributeTsMarshalType(枚举名以本文为准,含 OpaqueValue)。 外部配置: 预编译程序集可通过 XML 配置等价规则,见 §9


1. 概述

[TsMarshalAs] 可标注于:

  • 参数返回值字段属性
  • 类型class / struct 上的类型级默认)

不可 标注于 方法(绑定期 TsMarshalAsConfigurationException 或 Mono 路径告警回退)。

不可 作用于 未确定(open / 含泛型形参)的 CLR 类型位置(§1.1);可作用于 已闭合 的泛型类型位置(如 List<int> 形参)。XML 规则与 Attribute 同一约束(§9.3.1)。

覆盖标注须符合 §3 合法集合,否则 §4.1 回退 Default 并在 Editor 打错误日志。

public enum TsMarshalType
{
Default,
Object, // 强制 ByObj exotic(原 zlua UserData)
Bytes,
OpaqueValue,
UnpackedValues, // struct / closed generic struct:多 JS 实参 ↔ 列出的成员(不含 Nullable)
Table, // struct / closed generic struct / Nullable<struct>:单个 plain object ↔ 列出的成员
}

[AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.ReturnValue |
AttributeTargets.Field | AttributeTargets.Property |
AttributeTargets.Class | AttributeTargets.Struct)]
public sealed class TsMarshalAsAttribute : Attribute
{
public TsMarshalType MarshalType { get; }

/// <summary>
/// <see cref="TsMarshalType.Table"/> / <see cref="TsMarshalType.UnpackedValues"/> 必填。
/// 元素为 CLR 字段名或 property 名,可混合;顺序即 UnpackedValues 的实参顺序 / Table 的读写顺序。
/// 名字以 '?' 结尾表示 Table、JS→C# 时缺键不赋值(§6)。
/// </summary>
public string[] Members { get; set; }

public TsMarshalAsAttribute(TsMarshalType marshalType = TsMarshalType.Default);
}

命名说明: 文档与 XML 使用 TsMarshalType.Object(语义等同 zlua 的 UserData / ByObj exotic)。实现 C# 枚举名须与本文一致。

1.1 泛型:只允许「已确定」的类型位置

[TsMarshalAs](及等价 XML)不得用在仍含未绑定泛型形参的类型上:

禁止允许
类型级标在开放定义上类型级标在 非泛型 class / struct
形参/字段类型为泛型形参 T闭合构造:List<int> 形参等
泛型方法上未确定的槽位同一方法上类型已闭合的槽位

违反 → Il2Cpp Generate / XML 失败Mono Attribute 路径见 §4.1


2. TsMarshalType 枚举说明

适用方向说明
Default双向使用 01-OVERVIEW.md 默认规则。
Object双向 可标注于 托管引用类型struct(§3)。强制 ByObj / ByVal exotic 形态。
实质有效目标: 几乎只有 string——默认 C#↔JS 为 JS string,标注后改为 ByObj exotic(托管 System.String
class / 数组 / 普通 struct: 默认已是 exotic,标注与 Default 等价
Delegate 可标注但 无实质作用(仍按 09-FUNCTION.md
Bytes双向C# byte[] ↔ JS string(原始 octet)。Pop 时 不接受 exotic / Array(标注于 byte[] 时)。
OpaqueValue仅 C# → JSPush OpaqueValue(见 04-OPAQUE.md)。
ref/in/out 默认已是 OpaqueValue
• by-val 可对 struct / 引用 / enum / 指针等显式标注;基元IntPtr 族禁止 by-val 标注
• 脚本经 zts.get_opaquevalue / zts.set_opaquevalue
UnpackedValues双向普通 struct / closed 泛型 struct不含 Nullable)。Members 列出的成员与 连续多个 JS 实参 互转;占用 N 个实参槽(§5.6)
Table双向struct / closed 泛型 struct / Nullable<struct>。单个 plain object{} 键值)↔ 成员;Nullable 无值 → nullundefined(§6);须 Members

3. 各类型的合法 TsMarshalType 集合

每个 CLR 槽位仅允许 §2 中相容的值(Default 对所有类型均合法)。下表列出 Default 之外 可显式标注的值。

OpaqueValue 仅 C#→JS 方向可标注(§3.1)。基元IntPtr Default

C# 类型(分类)合法 TsMarshalTypeDefault 除外)说明
基元(无;Defaultref/in/out 基元 → 默认 OpaqueValue
IntPtr / UIntPtr / nint / nuint(无;Default整型数值 Marshal
stringObjectBytesOpaqueValueObject → ByObj exotic
byte[]BytesObjectOpaqueValue
T[](szarray)ObjectOpaqueValue
T[,…](mdarray)ObjectOpaqueValueJS→C# 因标注接受 Array
enumOpaqueValueboxed 用 zts.box
structObjectOpaqueValueTableUnpackedValues
class / interfaceObjectOpaqueValue不可 Table / UnpackedValues
DelegateObjectOpaqueValueObject 无实质作用
objectObjectOpaqueValue
ref / in / out T(通常无需标注)C#→JS 默认 OpaqueValue
Nullable<T>T struct)ObjectOpaqueValueTable不含 UnpackedValues
非托管指针 / 函数指针OpaqueValue默认可 Pointer 透传
TypedReference(默认即 OpaqueValue)其它非法
decimalOpaqueValue默认暂不支持
ref structOpaqueValue
params T[]OpaqueValue(仅 C#→JS)默认同 szarray

3.1 方向过滤

TsMarshalType允许标注的方向
ObjectBytesTableUnpackedValues双向
OpaqueValue仅 C# → JS;标于纯 JS→C# 形参 → 非法

4. 非法标注与配置错误

4.1 Mono Attribute:日志 + 回退 Default

Mono 解析 Attribute 时非法组合 → Default 处理 + Editor 错误日志;Player 静默回退。

4.2 Il2Cpp Generate / XML:可硬失败

同类配置错误可 中止 Generate,不写入 Player 绑定表。

运行时 arity 错误(UnpackedValues 实参个数 ≠ Members.Length)→ throw Error('zts: …')


5. TableUnpackedValues(值类型)

目标TableUnpackedValues
普通 struct / closed 泛型 struct
Nullable<T>(T 为 struct)
class / interface / ref struct / 基元 / enum

默认: 接受 plain object 或多实参组装;须显式标注 + Members

5.1 成员名单

  • string[]:CLR field / property 名,可混合。
  • Nullable<T> + Table 名单解析在 T 上。
  • UnpackedValues 顺序 = JS 实参顺序;Table = 成员名(字符串键)。

5.2 UnpackedValues 示例

void Foo([TsMarshalAs(TsMarshalType.UnpackedValues, Members = new[] { "Y", "X" })] Vector2 v);
Foo(2.0, 1.0); // 第一实参 → Y,第二 → X
[return: TsMarshalAs(TsMarshalType.UnpackedValues, Members = new[] { "X", "Y" })]
Vector2 GetPos();
// JS: const [x, y] = CS.Demo.GetPos(); // 或多返回值绑定为 Array,见 bridge 约定

5.3 Table 示例

void Foo([TsMarshalAs(TsMarshalType.Table, Members = new[] { "X", "Y" })] Vector2 v);
Foo({ X: 1, Y: 2 });
Bar(null); // Nullable 无值
Bar(undefined); // 同无值(§01 §2.3)
Bar({ X: 1, Y: 2 });

5.4 嵌套限制

名单成员若为 struct,默认 自动展开;须该成员自身标注或走 exotic 默认路径(v1 可限制名单仅含标量 / enum / string)。

5.5 实参槽占用与调用约定

TsMarshalType占用 JS 实参槽数
Table 及其它(除 UnpackedValues)1
UnpackedValuesNN = Members.Length
  • JS → C#: 桥接按 实参光标 推进:argIndex += 该形参槽数
  • 重载分派: 「JS 实参个数」= 各形参槽数之和(见 ../04-METHOD-OVERLOAD.md)。
  • C# → JS 返回值: Table → plain object;UnpackedValuesJS Array(长度 N,按 Members 顺序)或 bridge 约定的多值形态。

6. Table 可选成员:? 后缀

TableJS → C#

  • "Tag?" → plain object 缺该键 时跳过赋值。
  • ? 的成员缺键 → throw Error
  • UnpackedValues 不支持 ?
Foo({ X: 1, Y: 2 }); // OK;Tag 默认
Foo({ X: 1 }); // 缺 Y → throw

7. params T[] 形参

范围: 普通 C# 方法 / 构造函数上的 paramsGetFunction delegate bridge 上的 params 不支持(见 09-FUNCTION.md)。

Marshal: 与 szarray 相同(C#→JS ByObj exotic;JS→C# exoticArray)。

传入C# 收到
ByObj exotic该数组引用
[]T[0]
Array { … }构造的 T[n]
nullnull
undefinedthrow(§01 §2.3; 空数组)

禁止 JS 多实参隐式收集: Sum(1, 2, 3) 非法;须 Sum([1,2,3]) 或传 exotic。

CS.Demo.Sum([1, 2, 3]);
CS.Demo.Sum([]); // T[0]
CS.Demo.Prefix(0, [1, 2]);
CS.Demo.Sum(null);

8. 解析优先级

  1. 参数 / 返回值上的 [TsMarshalAs](≠ Default)
  2. XML 对应规则(§9)
  3. 字段 / 属性上的 Attribute → XML
  4. 类型级(仅非泛型)Attribute → XML
  5. 01-OVERVIEW.md 内置默认

Attribute 优先于 XML。 非法标注:Mono 回退 §4.1;Generate 失败 §4.2。


9. XML 外部配置(预编译程序集)

[TsAlias] 分离: 别名使用 tsAliasXmlPaths / 根元素 TsAlias(见 ../04-METHOD-OVERLOAD.md §5.4)。

9.1 配置入口

Editor ZTS.SettingsProjectSettings/ZTS.asset):

  • marshalAsXmlPaths:仅承载 ZTSMarshalAs 规则
  • tsAliasXmlPaths:别名专用(分开配置)

9.2 文件格式

<?xml version="1.0" encoding="utf-8"?>
<ZTSMarshalAs version="1">
<Assembly name="UnityEngine.CoreModule">
<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>
</Assembly>
</ZTSMarshalAs>
元素 / 属性含义
Assembly/@name程序集简单名
Type/@fullNameCLR 全名;嵌套 Outer+Inner;泛型声明 Foo`1
Method/@name / @signature与 overload 文档一致;不含返回类型
Param/@index0-based不含 this
MarshalAs/@typeDefault / Object / Bytes / OpaqueValue / UnpackedValues / Table
MarshalAs/@members逗号分隔;? 表示 Table 可选键

禁止: 方法级直接 MarshalAsParamname 定位;历史名 UserData → 须写 Object

9.3 校验与重复

  • 加载时元数据校验;闭合泛型实例作 Type 容器 → 失败
  • 同一目标键重复规则 → 整次加载失败
  • Attribute 与 XML 同目标:Attribute 生效

9.4 Mono 运行时

按 Settings 惰性加载;热路径 O(1) 查表;拼字符串匹配。

9.5 Il2Cpp

Generate 写入 C++ 表(仅名字,无 metadata token);Player 解析 XML。


10. 相关文档

主题文档
默认矩阵 / undefined/null01-OVERVIEW.md
OpaqueValue04-OPAQUE.md
struct05-STRUCT.md
数组 / Bytes07-ARRAY.md
方法别名 XML../04-METHOD-OVERLOAD.md §5.4