必须为类添加[serializable]标记才能用binaryformatter反序列化,但.net core 5+默认禁用该不安全方式;推荐使用system.text.json流式反序列化json文件,注意处理bom、换行符、类型匹配等问题。

反序列化前必须确认类型是否标记了 [Serializable]
如果类没加 [Serializable] 特性,BinaryFormatter 会直接抛出 SerializationException。即使类里所有字段都是可序列化的,缺这个标记也不行。
注意:.NET Core 5+ 和 .NET 6+ 默认禁用 BinaryFormatter,因为它有严重安全风险——反序列化任意二进制数据可能触发远程代码执行。除非你完全控制文件来源且运行在可信环境,否则别用它。
- 替代方案优先选
System.Text.Json(推荐)或Newtonsoft.Json - 若必须用二进制格式(如老系统兼容),改用
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter前,得在项目文件中显式启用:<enableunsafebinaryformatterserialization>true</enableunsafebinaryformatterserialization> - 标记类时,私有字段默认会被序列化;不想保存的字段加
[NonSerialized]
用 System.Text.Json 从 JSON 文件读取对象最安全
这是目前 C# 官方主推的方式,无需额外 NuGet 包(.NET Core 3.0+ 内置),默认忽略不可访问成员,不执行构造函数,天然防反序列化攻击。
示例代码片段:
var json = File.ReadAllText("data.json"); var obj = JsonSerializer.Deserialize<MyClass>(json);
- 确保
MyClass有公共 getter/setter 的属性,或配置JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase来匹配小驼峰命名 - 如果文件含日期字符串,注意默认只支持 ISO 8601 格式(如
"2023-10-05T08:30:00"),非标准格式需自定义JsonConverter<datetime></datetime> - 遇到
JsonException,大概率是 JSON 格式错误或字段类型不匹配,可用JsonDocument.Parse(json)先验证结构
用 FileStream + JsonSerializer 避免大文件内存爆涨
直接读整个文件到字符串再反序列化,对几百 MB 的 JSON 文件很容易 OOM。应流式处理。
正确做法:
using var stream = File.OpenRead("big-data.json"); var obj = await JsonSerializer.DeserializeAsync<MyClass>(stream);
- 同步版本用
Deserialize<t>(Stream)</t>,异步版本用DeserializeAsync<t>(Stream)</t> - 不要用
File.ReadAllBytes()再转MemoryStream—— 这和读字符串一样占双倍内存 - 如果目标类型是集合(如
List<item></item>),且文件是数组格式,可直接反序列化;如果是包裹对象(如{"items":[...]}),得先定义对应包装类
反序列化失败时,别只看异常消息
JsonException 的 Message 通常只说“invalid Token”,但真正问题往往藏在 LineNumber 和 BytePositionInLine 属性里。
- 捕获异常后打印这两个值,能快速定位 JSON 中哪一行哪个字符出错
- 常见隐形坑:BOM 头(UTF-8 with BOM)、windows 换行符混入字符串字段、浮点数用了本地化小数点(如
"3,14"而非"3.14") - 调试阶段可在反序列化前用
JsonSerializer.Serialize(obj)把对象打出来,对比原始文件,看差异在哪
类型不匹配比语法错误更难察觉——比如 JSON 里是字符串 "123",而 C# 字段是 int,默认会失败;此时可加 JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()) 或自定义 converter 处理。