Skip to main content

04-SPECIAL-TYPES

文档站副本

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

--- sidebar_position: 21 title: "特殊类型的分派行为"

04 — 特殊类型的分派行为

本文档汇总 enumNullable<T>struct数组委托(delegate) 在 exotic 布局与属性分派上的特例。值如何 Push/Pop、ByVal/ByObj payload 布局等 Marshal 细节见 ../marshal/ 各分册;本文只描述 JavaScript 脚本可见 的对象结构、内部方法与索引入口。

关联文档: 通用布局 → 01-LAYOUT.md;索引算法 → 02-INDEX.md;绑定规则 → 03-BINDING.md


1. 枚举(enum)

1.1 类型对象与静态访问

enum 经 CSharp[assembly][typeFullName] 解析为类型对象 E,带 __enum : true、STO 与 ByObj IEO。 __byvalInstanceProto

Bind 期将该 enum 所有 public static literal 字段写入 E 本体number(值为 C# underlying 整型,通常为 number不是 bigint)。读 E.Red 时若键已在 E 上,不触发分派 [[Get]]

STO 提供 属性 get/set(静态三表),但 [[Construct]]_default禁止 new EnumType(...) 构造实例,禁止E 或 STO 上挂 _ctor

对 enum 常量的赋值:属性 set strict throw,与 static readonly 一致。

1.2 Boxed 实例

需要 boxed enum(ByObj exotic object)时使用 zts.box../05-LIB.md),提供类型对象构造入口:

const Color = CSharp.AC['MyGame.Color'];
const redBox = zts.box(Color, Color.Red);

产物挂接 E.__byobjInstanceProto__zts_ud_kind"byobj"。实例三表通常为空或极少成员(enum 无 public 实例 field/method);toString 建议形如 EnumFullName(value)

默认跨边界传参仍用 number../marshal/08-ENUM.md);zts.box 仅用于需要 object 形参、装箱语义的场景。

1.3 与 class / struct 对比(分派)

enum
类型对象常量number 键
[[Construct]]
_default
实例 exotic objectzts.box → ByObj
继承扁平化(enum 无继承链合并)

2. Nullable<T>(闭合值类型)

System.Nullable\1zts.make_generic_type闭合为类型对象N,带 **__nullable : true**,与 __struct/__enum` 互斥。

2.1 布局特例

  • __byvalInstanceProto __byobjInstanceProto IEO。
  • STO [[Construct]] 与可选 toString静态成员属性 get/set(不暴露 Nullable 类型自身的 static 成员绑定)。

2.2 [[Construct]] 语义

new N(...)N(...)(若实现允许 callable)构造的是 element 类型 T 的有值表示不是 Nullable 包装实例。native 将 construct 绑定到 element 类型 的构造逻辑(与 new T(...) / 基元转换一致):

const NullableInt = zts.make_generic_type(
CSharp.mscorlib['System.Nullable`1'],
zts.types.int32
);
const n = new NullableInt(42); // JS number,非 exotic object

const NullablePoint = zts.make_generic_type(
CSharp.mscorlib['System.Nullable`1'],
Point2D
);
const p = new NullablePoint(1, 2); // Point2D ByVal exotic object
T 种类N(...) 返回值
基元对应 JS 基元(boolean / number)
structT 的 ByVal exotic object
enum不支持此入口(enum 无 construct)

null / 无值 不经 N(...) 表达;向 C# 传 Nullable<T> 的 null 时直接传 JS null不是 undefined;见 ../00-OVERVIEW.md §1.4、../marshal/01-OVERVIEW.md)。


3. 值类型 struct

struct 类型对象含 __struct : true,同时挂 __byvalInstanceProto__byobjInstanceProto(见 01-LAYOUT.md §4)。

3.1 静态入口

入口位置语义
new Type(...)STO [[Construct]]有参 public 构造 → ByVal exotic object(与规范默认构造产物一致)
Type._default()STO 保留键 _default,经静态属性 get → STO 回退无参 零初始化 实例,等价 default(T)调用用户带参构造

禁止 _ctor 字段;禁止 enum/Nullable 的 _default

3.2 实例成员与双 IEO

  • ByVal exotic object[[DispatchProto]] = T.__byvalInstanceProto;字段/方法经 ByVal 三表索引;this 指向 payload(../marshal/05-STRUCT.md)。
  • ByObj exotic object(boxed struct):[[DispatchProto]] = T.__byobjInstanceProto;同一成员名,ByObj 三表 function。
  • 静态成员T / STO 访问,与 class 路径相同。
const p = new Point(3, 4);
p.translate(1, 0); // ✅ 方法调用,自动 ByVal this

const move = p.translate;
move(1, 0); // ❌ 提取 function,不绑定 this(§02-INDEX §3.2)

struct C# 实例继承;Bind 期 合并基类实例成员(值类型无派生实例继承场景)。可选 zts.box 在 ByVal 与 ByObj 间转换(marshal 分册)。


4. 数组(szarray / mdarray)

数组类型对象结构与普通引用类型类似:仅 ByObj IEO(数组对象为 Il2CppArray* / 等价引用)。STO [[Construct]](数组实例由 zts.new_szarray_* / zts.new_mdarray_* 创建,见 ../02-TYPE-SYSTEM.md)。

4.1 实例特性

特性行为
lengthszarray:arr.length = Length;mdarray:arr.length = 各维 GetLength(d)(可寻址元素总数),不是单维长度
整数键 arr[i]实现;读写在运行时 [[Get]]/[[Set]] 整数键
属性 get/set走实例三表

4.2 元素访问:get / set

Bind 期向实例 methodTable 注册 native 方法 get / set get_Item 命名):

arr.set(0, 10); // szarray:1 个下标 + value
console.assert(arr.get(0) === 10);

matrix.set(0, 1, 7); // mdarray:rank 个下标 + value

实参个数:get 须等于 rankset 须等于 rank + 1(末参为 value)。下标为 C# 各维下标(含 lowerBound),须为 number禁止 bigint 下标)。越界 → throw new Error('zts: …')

get / set实例方法,须 arr.get(0) 方法调用形式;提取后调用遵守 02-INDEX.md §3.2。

仍可通过三表绑定的 GetValue / SetValue 等方法访问;基元断言优先 get(未装箱)。与 zts.to_array 的 0 基 JS Array 语义不同,见 ../marshal/07-ARRAY.md


5. 委托(delegate)

委托类型对象 + ByObj IEO。委托 实例 exotic object 在 ByObj IEO 上额外注册 [[Call]]

const cb = new SomeDelegate((x) => x * 2);
const result = cb(21); // 等价 invoke;非 cb.Invoke(21) 必需

[[Call]] 实参个数须与 Invoke 签名一致;JS function → delegate 的 Marshal 见 ../marshal/09-FUNCTION.md。静态成员(若有)仍经 STO 三表; event 子对象。

委托实例 不是 典型「实例 method + receiver」模型:[[Call]] 直接 invoke multicast; [[NeedsReceiver]] 提取问题。


6. 其它类型(摘要)

类型分派要点
class__byobjInstanceProto[[Construct]] → 实例构造;继承成员 Bind 期扁平化
interface可解析类型对象;通常无 public 构造,new 不可用
抽象类仅 public 构造可 new;protected 构造对 JS 不可见
静态类仅静态三表;无 [[Construct]]、无 IEO

7. Marshal 交叉引用

主题文档
enum 默认 number 与 box../marshal/08-ENUM.md
struct ByVal / ByObj../marshal/05-STRUCT.md
class / 引用门面../marshal/06-CLASS.md
数组创建与 get/set../marshal/07-ARRAY.md
Delegate ↔ JS function../marshal/09-FUNCTION.md
Nullable null / 有值../marshal/01-OVERVIEW.md
undefined vs null../marshal/01-OVERVIEW.md

分派层只保证 入口与索引语义 与上表一致;具体栈上类型校验与 GC 行为以 marshal 分册为准。


8. v1 数值类型限制

场景规范
enum 常量number
数组下标number(整数)
CLR 整数通道number不支持 bigint
脚本传入 bigint 给 C# 整数参数throw zts: bigint is not supported for CLR integer types in v1(或等价)