参考文档
ByteWriter、ByteReader、Json、IJsonSerializable 的所有成员。
全部位于 Udonite.Serialization。
ByteWriter
new ByteWriter() // 默认初始容量
new ByteWriter(64) // 以字节为单位的初始容量,需要时会继续增长
| 成员 | 写入内容 |
|---|---|
WriteByte(byte) |
一个字节 |
WriteBoolean(bool), WriteChar(char) |
固定长度 |
WriteInt16, WriteUInt16, WriteInt32, WriteUInt32, WriteSingle, WriteDouble |
固定长度,基于 System.BitConverter |
WriteString(string) |
带长度前缀(null 记为 0),逐字符写入 |
WriteBytes(byte[]) |
带长度前缀的原始字节——嵌套负载经由此处传递 |
WriteVector2, WriteVector3, WriteQuaternion |
逐分量写入 |
WriteLength(int) |
用尽可能少的字节表示一个数量——127 以内 1 字节,16383 以内 2 字节 |
Position { get; } |
目前已写入的字节数 |
Reset() |
不重新分配缓冲区,直接回退到空 |
ToArray() |
恰好大小的拷贝——多分配出来的尾部不包含在内 |
所有 Write 方法都返回 this,可以链式调用:new ByteWriter().WriteInt32(1).WriteString("a")。
刻意收窄的核心,不是 System.BitConverter 的完整照搬。 没有 64 位整数,没有带符号的 8 位,没有比 short 更窄的 16 位,也没有 Vector2Int。一个 reached 的类会被整体编译进去,声明的每个方法都会在程序存活期间一直占用堆——这里只保留负载真正可能携带的那些类型。
ByteReader
new ByteReader(bytes)
| 成员 | 读取内容 |
|---|---|
ReadByte() |
一个字节 |
ReadBoolean(), ReadChar() |
固定长度 |
ReadInt16, ReadUInt16, ReadInt32, ReadUInt32, ReadSingle, ReadDouble |
固定长度 |
ReadString() |
读回一个 WriteString 负载 |
ReadBytes() |
读回一个 WriteBytes 负载 |
ReadVector2, ReadVector3, ReadQuaternion |
逐分量读取 |
ReadLength() |
读回一个 WriteLength 数量 |
Position { get; }, Length { get; }, LengthRemaining { get; } |
游标位置、缓冲区大小、剩余字节数 |
SetBuffer(byte[]) |
在另一个缓冲区上复用这个 reader,游标重置到开头 |
读到缓冲区末尾之外不会抛异常,而是打日志并返回该类型的默认值。 异常处理在 Udonite 里还未经验证,一个损坏或被截断的缓冲区不应该把读取它的 behaviour 一起拖垮。请按写入时的顺序读取,并读完你写入的全部内容——这里没有任何东西能告诉你格式错了,只能告诉你读取因为字节不够而停下了。
Json
| 成员 | 作用 |
|---|---|
Serialize<T>(T) |
通过 T 自己的 ToJson() 把它打包成 JSON。T 为 null 或 VRCJson 拒绝时返回 null |
Deserialize<T>(string) |
解析 JSON,构造一个新的 T(where T : class, IJsonSerializable, new()),通过 FromJson 填充它。JSON 不合法时返回 null |
Serialize(DataToken), Serialize(DataToken, bool pretty) |
低层形式,用于没有固定类型、临时拼装的 JSON |
Deserialize(string) |
直接返回一个 DataToken?,同一条逃生通道的反方向 |
失败时统一返回 null,而不是 bool 加 out 参数的组合。
没有会遍历任意类型字段的、基于反射的 Serialize<T>。 Udon 完全没有反射——这是直接对着编译器验证过的事实,不是猜测。Deserialize<T> 的 where T : new() 也不是反射:它是 C# 编译器在调用处解析的约束,所以即便这里没法调用 Activator.CreateInstance,它照样能编译通过。
每一个 JSON 数字都会被解析成 TokenType.Double,哪怕写的是一个普通整数。 {"score": 42} 解析出来的 token,.Int 会在上面抛异常——只有 .Double(再转换成你需要的类型)能读出来。这是 VRCJson 自身的特性,这个封装改变不了。
IJsonSerializable
| 成员 | 作用 |
|---|---|
DataToken ToJson() |
把这个实例打包起来,通常打包成 DataDictionary |
void FromJson(DataToken token) |
用 ToJson 产生的内容填充这个实例 |
两个方法都没提到的字段,既不会被发送,也不会被填充——这里没有任何机制会自动检查一个类型的成员。FromJson 修改的是被调用的那个实例本身,而不是返回一个新实例,这和 Udonite Net 里 NetworkEvent.Deserialize 的做法一样:这里要么需要 new(),要么需要调用方已经准备好一个实例,否则就没有办法构造出任意类型。