.NET 5+ 默认推荐 System.Text.Json,性能好、内存占用低、原生支持异步,但对 DateTime、Dictionary、Nullable 等类型处理更严格,需注意循环引用、中文编码、属性可见性及命名策略等问题。

用 System.Text.Json 序列化对象最稳妥
.NET 5+ 默认推荐 System.Text.Json,性能好、内存占用低、原生支持异步,且不依赖第三方包。它对 DateTime、Dictionary、Nullable 类型的默认处理比 Newtonsoft.Json 更严格,也更可控。
常见错误现象:NullReferenceException(没处理可空引用)、NotSupportedException(序列化字段含循环引用或非 public 成员)、中文变 Unicode(如 "\u4f60\u597d")。
- 默认只序列化
public字段和属性;若需序列化private或internal成员,得加[JsonInclude]或配置JsonSerializerOptions.IncludeFields = true - 中文乱码?加
new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping } - 忽略某个属性?加
[JsonIgnore],或在选项中用DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - 时间格式不对?用
Converters.Add(new JsonStringEnumConverter())或自定义JsonConverter<DateTime>
示例:
var json = JsonSerializer.Serialize(person, new JsonSerializerOptions { WriteIndented = true });
遇到循环引用必须手动断开
System.Text.Json 默认不支持对象间循环引用(比如 A.User → B,B.Posts → A),直接序列化会抛 InvalidOperationException: A possible object cycle was detected。它不像 Newtonsoft.Json 那样提供 ReferenceLoopHandling.Ignore 这种“自动绕过”开关。
- 最干净的做法:用 DTO(数据传输对象)提前剥离循环结构,而不是把实体类直接扔进
Serialize() - 临时方案:在属性上加
[JsonIgnore],或用JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault配合合理默认值 - 别试图用
PreserveReferencesHandling——System.Text.Json根本没有这个选项
Newtonsoft.Json 还值得用吗?看场景
如果项目还在用 .NET Framework,或依赖大量 JsonPropertyAttribute、JsonConverter 自定义逻辑,或需要动态修改序列化行为(比如运行时决定是否忽略某字段),Newtonsoft.Json 仍是更灵活的选择。
但要注意:它默认开启循环引用检测(报错),要显式关掉:
var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
- 它默认序列化
privateset 属性,System.Text.Json不行 - 它的日期解析更宽松(如能自动识别
"2023-10-05"和"/Date(1696464000000)/") - 但包体积大、GC 压力高,尤其高频小对象序列化时差异明显
- 和 ASP.NET Core 6+ 深度集成的是
System.Text.Json,混用可能引发JsonSerializerOptions冲突
反序列化时类型不匹配最容易出静默错误
比如用 JsonSerializer.Deserialize<Person>(json),但 JSON 里字段名是 "full_name" 而 C# 属性叫 FullName,默认情况下 System.Text.Json 直接跳过该字段,不报错也不赋值 —— 对象看起来“成功创建”,实则关键数据丢失。
- 务必检查字段命名策略:加
PropertyNamingPolicy = JsonNamingPolicy.CamelCase或用[JsonPropertyName("full_name")] - 启用严格模式:设置
UnknownTypeHandling = JsonUnknownTypeHandling.Reserved(.NET 7+)或手动校验返回对象状态 - 别依赖
try-catch捕获反序列化异常来判断失败——很多类型不匹配是静默失败,不是抛异常 - 嵌套对象为
null时,反序列化后对应属性仍是null,不会自动 new 实例,记得初始化或用可空引用检查
复杂点在于:JSON 结构和 C# 类型之间没有编译期约束,运行时才暴露问题。哪怕单元测试覆盖了典型用例,字段增减、前后端协议微调都可能让反序列化结果偏离预期——这点比序列化本身更难防。










