如何在C#中基于ISerializable实现Vector2[]的字节序列化?
解决C#中ISerializable处理复合字典结构的问题
针对你遇到的Dictionary<MyEnum, Vector2[]>手动序列化问题,有两种直接可行的方案,完全适配ISerializable的要求,同时避免键重复:
方案一:使用层级化唯一键名
通过给每个序列化项添加层级索引前缀,确保键名绝对唯一,完全贴合SerializationInfo的键值对存储逻辑。
序列化(GetObjectData方法)
public void GetObjectData(SerializationInfo info, StreamingContext context) { // 先存入字典元素总数 info.AddValue("DictCount", dict.Count); int entryIndex = 0; foreach (var kvp in dict) { // 存储枚举键的ordinal值 info.AddValue($"DictEntry_{entryIndex}_KeyOrdinal", (int)kvp.Key); // 存储当前数组的长度 info.AddValue($"DictEntry_{entryIndex}_ArrayLength", kvp.Value.Length); // 逐个存储Vector2的X和Y for (int vecIndex = 0; vecIndex < kvp.Value.Length; vecIndex++) { var vec = kvp.Value[vecIndex]; info.AddValue($"DictEntry_{entryIndex}_Vector_{vecIndex}_X", vec.X); info.AddValue($"DictEntry_{entryIndex}_Vector_{vecIndex}_Y", vec.Y); } entryIndex++; } }
反序列化(专用构造函数)
protected MyClass(SerializationInfo info, StreamingContext context) { dict = new Dictionary<MyEnum, Vector2[]>(); int dictCount = info.GetInt32("DictCount"); for (int entryIndex = 0; entryIndex < dictCount; entryIndex++) { // 读取枚举键 var keyOrdinal = info.GetInt32($"DictEntry_{entryIndex}_KeyOrdinal"); MyEnum key = (MyEnum)keyOrdinal; // 读取数组长度并初始化数组 int arrayLength = info.GetInt32($"DictEntry_{entryIndex}_ArrayLength"); Vector2[] vecArray = new Vector2[arrayLength]; // 逐个读取Vector2的X和Y并赋值 for (int vecIndex = 0; vecIndex < arrayLength; vecIndex++) { float x = info.GetSingle($"DictEntry_{entryIndex}_Vector_{vecIndex}_X"); float y = info.GetSingle($"DictEntry_{entryIndex}_Vector_{vecIndex}_Y"); vecArray[vecIndex] = new Vector2(x, y); } dict.Add(key, vecArray); } }
这种方式逻辑清晰,每个键都带有明确的层级索引,完全不会出现键重复的问题,后续扩展其他数组也只需延续相同的命名规则即可。
方案二:复刻Java的字节流写法
如果更习惯Java中直接写入原始数据的方式,可以把整个字典序列化为一个字节数组,再存入SerializationInfo,反序列化时再按顺序读取。
序列化(GetObjectData方法)
public void GetObjectData(SerializationInfo info, StreamingContext context) { using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) { // 写入字典元素数 writer.Write(dict.Count); foreach (var kvp in dict) { // 写入枚举ordinal writer.Write((int)kvp.Key); // 写入数组长度 writer.Write(kvp.Value.Length); // 逐个写入Vector2的X和Y foreach (var vec in kvp.Value) { writer.Write(vec.X); writer.Write(vec.Y); } } // 将字节数组存入SerializationInfo info.AddValue("DictRawData", ms.ToArray()); } }
反序列化(专用构造函数)
protected MyClass(SerializationInfo info, StreamingContext context) { dict = new Dictionary<MyEnum, Vector2[]>(); byte[] rawData = (byte[])info.GetValue("DictRawData", typeof(byte[])); using (var ms = new MemoryStream(rawData)) using (var reader = new BinaryReader(ms)) { int dictCount = reader.ReadInt32(); for (int i = 0; i < dictCount; i++) { // 读取枚举键 MyEnum key = (MyEnum)reader.ReadInt32(); // 读取数组长度 int arrayLength = reader.ReadInt32(); Vector2[] vecArray = new Vector2[arrayLength]; for (int j = 0; j < arrayLength; j++) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); vecArray[j] = new Vector2(x, y); } dict.Add(key, vecArray); } } }
这种方式完全和你熟悉的Java逻辑一致,不需要担心键的问题,所有数据打包成一个字节数组存储,缺点是序列化后的内容可读性差,但性能和简洁性更好。
内容的提问来源于stack exchange,提问作者SK19
相关产品推荐
相关产品推荐

