如何在C#中不使用BinaryFormatter反序列化其序列化的数据
不用BinaryFormatter反序列化BinaryFormatter序列化数据的方法
方法一:手动解析二进制流
BinaryFormatter的序列化输出有固定结构,核心包含魔法头、类型元数据、实际字段值三部分。针对已知结构的目标类型,可按规则逐字节解析:
验证并跳过魔法头
BinaryFormatter开头是固定字节序列:0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,读取并跳过这17字节即可。匹配字段顺序解析值
提前确认原类型的字段名称、类型和顺序,按BinaryFormatter的序列化规则读取对应字节并转换:- 值类型(int、bool、DateTime等):直接读取对应字节长度转换
- 引用类型(string、自定义类等):处理长度标记后读取内容,嵌套类需递归解析
示例代码(针对自定义User类型):
public class User { public int Id { get; set; } public string Name { get; set; } public DateTime CreateTime { get; set; } } public static User DeserializeUser(byte[] serializedData) { using var ms = new MemoryStream(serializedData); using var reader = new BinaryReader(ms); // 跳过魔法头 reader.ReadBytes(17); // 跳过类型元数据(已知结构时可直接跳过,复杂场景需解析元数据匹配字段) // 解析Id var userId = reader.ReadInt32(); // 解析Name:先读长度,再读Unicode字节转字符串 var nameLength = reader.ReadInt32(); var nameBytes = reader.ReadBytes(nameLength); var userName = Encoding.Unicode.GetString(nameBytes); // 解析DateTime:读取64位Ticks值转换 var createTicks = reader.ReadInt64(); var createTime = new DateTime(createTicks); return new User { Id = userId, Name = userName, CreateTime = createTime }; }
手动解析仅适用于结构简单、字段明确的场景,泛型、继承类、循环引用等复杂结构会大幅提升解析难度。
方法二:基于反射实现通用解析
通过反射获取目标类型的字段信息,按BinaryFormatter规则批量读取赋值,适用于字段较多但结构不复杂的类型:
public static T Deserialize<T>(byte[] serializedData) where T : new() { using var ms = new MemoryStream(serializedData); using var reader = new BinaryReader(ms); // 跳过魔法头 reader.ReadBytes(17); // 跳过类型元数据(需确保目标类型与原类型字段顺序、类型完全匹配) var targetObj = new T(); var fields = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var field in fields) { if (field.FieldType == typeof(int)) field.SetValue(targetObj, reader.ReadInt32()); else if (field.FieldType == typeof(string)) { var strLen = reader.ReadInt32(); var strBytes = reader.ReadBytes(strLen); field.SetValue(targetObj, Encoding.Unicode.GetString(strBytes)); } else if (field.FieldType == typeof(DateTime)) field.SetValue(targetObj, new DateTime(reader.ReadInt64())); // 可扩展支持更多类型(如bool、long、float等) } return targetObj; }
关键注意事项
- BinaryFormatter格式包含.NET特定类型元数据,跨版本或跨平台可能存在兼容性问题
- 解析时必须严格遵循BinaryFormatter的序列化规则,包括空值标记、引用重复处理等细节
- 若原类型涉及继承、泛型或循环引用,手动解析复杂度极高,建议优先获取原类型定义辅助解析
内容的提问来源于stack exchange,提问作者subbaraoc
相关产品推荐
相关产品推荐

