Skip to main content
文档站副本

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

Marshal 总览 — 默认规则矩阵

规范性: 未标注 [TsMarshalAs](或标注为 TsMarshalType.Default)时,各 CLR 类型在 C# ↔ JavaScript 双向调用中的默认 Marshal。 覆盖: 参数、返回值、字段、属性上的 [TsMarshalAs]02-MARSHAL-AS.md实现:impl/marshal/


1. 平台原则

  • Mono(Editor)与 Il2Cpp(Player)的 JS 可见 Marshal 语义一致;差异仅在实现层(零 GC、生成代码等),不改变脚本可观察行为。
  • 函数 / delegate: JS 调用 C# 方法时,delegate 形参接受 JS callablefunction 或等价),由桥接层隐式 marshal,详见 09-FUNCTION.md
  • GetFunction 取得的 delegate 调用 / delegate bridge(C# → JS)ref/out/in 的默认 Push 为 OpaqueValue,与 JS→C# 路径不同,见 03-BYREF.md04-OPAQUE.md
  • v1 禁止 bigint 作为 CLR 整数通道(见 ../00-OVERVIEW.md §1.3);整型基元、enum 底层、IntPtr 数值均经 number

2. undefinednull(完整边界规则)

QuickJS 同时存在 undefinednull禁止在规范层将二者无差别等同为「空」。

2.1 语义对照

JS 值含义典型场景
undefined「未提供 / 缺失」形参未传、可选参数省略、对象属性不存在(CLR 绑定 miss 除外)、C#→JS 可选参数未填充
null「显式空引用 / 无值」CLR 引用类型 nullNullable<T> 无值、脚本显式传入的空引用

不属于 undefined/null 值类型零值(0false)须用对应 JS 基元或 struct 构造产物。

2.2 C# → JavaScript(Push)

C# 源JS 形态
引用类型 nullnull
Nullable<T>T 为值类型)无值null不是 undefined
Nullable<T> 有值T 的默认 Push
可选参数未提供(C# 侧 invoke 使用默认值)由 bridge 决定是否在 JS 侧可见;GetFunction 回调形参若 C# 未传 optional 段,JS 侧对应位置为 undefined
值类型零值(0false 等)对应 number / boolean不是 undefined/null
void 返回JS 侧 undefined(无返回值)

2.3 JavaScript → C#(Pop)

JS 实参目标 CLR 类型行为
null引用类型 / delegate / 数组 / Nullable<T>null / 无值
undefined引用类型 / delegate / 数组(必选形参)throw Error('zts: argument missing: …') — 必选引用形参须显式传 null
undefinedNullable<T>视为 无值null
undefined带 CLR HasDefault 的可选形参(尾部连续段)使用 Bind 期物化 的默认值;消耗「实参个数」
undefined值类型(非 Nullable)必选形参throw Error
undefinedparams T[]02-MARSHAL-AS.md §7(等同空数组)

2.4 属性 / 索引与 Marshal 的边界

场景行为
读 C# 绑定成员 missthrow Error('zts: member not found: …')不是 undefined
读 JS 普通对象不存在的属性ECMAScript 默认 undefined(与 ZTS 无关)
C# 只写属性throw Error('zts: property has no getter: …')
数组 exotic get(i) 越界throw Error(见 ../02-TYPE-SYSTEM.md §7)

2.5 数组与空洞

形态Pop 为 szarray
nullC# null
undefined(作为整参传入)同 §2.3 必选引用规则
JS Array0..length-1 连续无空洞length 与最大索引一致);见 07-ARRAY.md
稀疏 Array / 带 holesthrow Error

2.6 示例

// 引用 null:显式 null
CS.Service.TakeString(null);

// 错误:undefined 不能代替 null(必选形参)
// CS.Service.TakeString(undefined); // throw

// Nullable 无值
CS.Service.TakeNullableInt(null); // OK
CS.Service.TakeNullableInt(undefined); // OK → 无值

// 可选参数
CS.Service.Log(msg, level); // level 省略 → undefined → 用 C# 默认
CS.Service.Log(msg); // 同上

// C#→JS:null 与 undefined
function onData(data) {
console.assert(data === null); // C# 传 null 引用
}
function onOptional(x, y) {
console.assert(y === undefined); // C# 未传 optional
}

3. 整数与 number

  • 唯一整数通道: JS number(IEEE-754 双精度)。禁止 bigint 隐式或显式映射为 long / IntPtr / enum 等(v1)。
  • Pop 整型基元 / enum 时:实参须为 numberNumber.isInteger(value) === trueNaN / Infinity 拒绝);再按目标类型范围校验。
  • Push 整型:number;超出 Number.MAX_SAFE_INTEGERulong 等须在文档化边界内行为一致(实现可 warn;越界 Pop → throw)。
  • char:按 Unicode 码点(16 位)整型 number
  • float/double:任意有限 number;向整型窄化时遵循 C# 收窄规则 + 整型校验。

4. 默认 Marshal 矩阵

C# 类型C# → JSJS → C#说明
boolbooleanboolean
charnumber(整数)number(整数)见 §3
byteulongnumber(整数)number(整数)禁止 bigint;见 §3
float / doublenumbernumber
IntPtr / UIntPtr / nint / nuintnumber(整数)number(整数)指针 数值;与 10-POINTER.md 非托管指针 不同
T*(非托管指针)Pointer(opaque internal handle)Pointer仅透传;见 10-POINTER.md
函数指针PointerPointer同上
System.TypedReferenceOpaqueValueOpaqueValue默认即此
stringstringstring
byte[]ByObj exoticByObj exoticArrayT[] 相同;[TsMarshalAs(Bytes)] → ↔ string
classByObj exoticByObj exotic引用身份;nullnull;门面 = 声明类型,见 06-CLASS.md
T[](szarray)ByObj exoticByObj exoticArray见 §5、07-ARRAY.md
T[,…](mdarray)ByObj exotic仅 ByObj exotic接受 JS Array
enumnumber(整数)number(整数)或 ByObj exotic(boxed)默认不推 exotic;boxed 仅经 zts.box;见 08-ENUM.md
structByVal exoticOpaqueValueByVal exoticnew Type(...)C#→Lua 常规见 05-STRUCT.mdref/in/out[OpaqueValue] → OpaqueValue
DelegatefunctionDelegate exoticfunctionDelegate exotic09-FUNCTION.md
objectByObj exoticSystem.Object 门面)boolean/number/string/exotic 等门面 = object;见 06-CLASS.md
Nullable<T>TnullTnullundefined(无值)§2
interfaceByObj exoticByObj exotic同 class;可 [TsMarshalAs(Object|UnpackedValues)] 仅 struct 场景不适用 interface
decimal暂不支持(默认)暂不支持v1 默认路径未纳入
ref struct05-STRUCT.md../05-LIB.md同左不能作为普通 by-val 默认传递
void(返回值)undefined

4.1 Exotic 形态说明

ByObj exoticByVal exotic、数组 ByObj、boxed enum、Delegate exotic 均为 QuickJS exotic object(internal slots + 三表分派),脚本侧经 . 访问成员(方法调用 obj.Method(args) 自动绑定 CLR this)。

与下列形态 不同

形态特征文档
OpaqueValue无成员分派;opaque exotic / internal handle04-OPAQUE.md
Pointer无 metatable / 三表;仅透传地址令牌10-POINTER.md

5. 数组(szarray / mdarray)

C# 类型C# → JSJS → C#
T[](szarray)ByObj exoticByObj exotic Array 形态(§5.2)
T[,…](mdarray)ByObj exotic仅 ByObj exotic
byte[]同 szarray(除非 [TsMarshalAs(Bytes)]同 szarray

5.1 C# → JS

数组实例 Push 为 ByObj exoticObjectRegistry 登记;元素访问经 get/set,见 ../02-TYPE-SYSTEM.md §7)。

5.2 JS → C#(szarray)

实参形态Pop 行为
ByObj exotic类型须与目标 T[] 一致(或兼容);传入数组引用
JS Array索引 0..n-1 连续、无空洞;按序 Pop 元素为 T,构造 T[n]
nullnull
undefined必选形参 → throw(§2.3)

5.3 JS → C#(mdarray)

ByObj exotic 或 null接受 JS Array。

5.4 Array 形态约束

  • 不接受 稀疏数组、Array 带 holes、或类数组 plain object(v1)。
  • 空数组 []T[0](零长度, null)。

6. 引用类型门面(摘要)

对所有 引用类型 形参、返回值、字段/属性:

概念含义
Identityexotic 内部槽持有的托管对象引用(运行时实际实例)
View / 门面实例分派 IEO 与成员可见性;唯一来源 = 本次 Marshal 的声明类型

规则摘要:

  1. C# → JS:按 声明类型 选择默认形态与 ByObj IEO;因运行时类型改挂更具体类型或改走 string 等特殊 Marshal。
  2. Downcast:仅 zts.cast(obj, targetType)(见 ../05-LIB.md)。
  3. 对象缓存:键 (identity, viewType)ObjectRegistry 槽位为 GC root(见 ../10-LIFETIME.md)。

完整规则见 06-CLASS.md


7. 相关文档

主题文档
[TsMarshalAs] 覆盖默认02-MARSHAL-AS.md
ref / in / out03-BYREF.md
OpaqueValue04-OPAQUE.md
struct05-STRUCT.md
class / interface06-CLASS.md
数组 / Bytes07-ARRAY.md
枚举08-ENUM.md
delegate / JS function09-FUNCTION.md
指针 / 不支持类型10-POINTER.md
重载与实参匹配../04-METHOD-OVERLOAD.md
zts.* API../05-LIB.md