jsonconvert.deserializeobject() 易出错因默认行为与直觉不符:大小写敏感、null 静默转默认值、非iso日期变minvalue、注释致异常;嵌套失败多因字段名/类型不匹配;动态解析掩盖拼写错误,新项目应优先用 system.text.json。

直接用 JsonConvert.DeserializeObject<t>()</t> 是最常用也最容易出错的方式——不是它不行,而是默认行为和你直觉不一致的地方太多,尤其从 Newtonsoft.Json 切过来的人,常在大小写、null 处理、日期格式上栽跟头。
为什么 JsonConvert.DeserializeObject 会静默失败或抛异常
Newtonsoft 默认宽容,但“宽容”不等于“鲁棒”。它会在很多边界情况里做隐式转换,反而掩盖问题:
-
JsonConvert.DeserializeObject<person>(json)</person>遇到"age": null时,会把int Age设为0,而不是报错——但这个0很可能不是业务意图 - JSON 字段是
"user_name",C# 属性叫UserName,不加[JsonProperty("user_name")]就读不到,也不会警告 - 遇到
"created_at": "2024/03/15"这种非 ISO 格式日期,DateTime属性会反序列化为DateTime.MinValue,且不抛异常 - 如果 JSON 里有注释(比如调试时手动加的
// note),默认直接报JsonReaderException
解析多层嵌套 JSON 时怎么避免属性全为 null
嵌套结构崩掉,90% 是字段名没对齐或类型不兼容。别靠猜,用这几招定位:
- 先用
JObject.Parse(json)把整个 JSON 加载成动态对象,再逐层检查:obj["data"]?["items"]?[0]?["id"]—— 这样能快速确认哪一层开始缺失 - 确保每一层嵌套类都定义了,且集合字段声明为
public List<item> Items { get; set; }</item>,而不是Item[]或IEnumerable<item></item>(后者反序列化可能失败) - 对可选字段,C# 属性必须显式支持 null:用
string?、int?、DateTimeOffset?,而不是string或DateTime - 如果 JSON 中数字有时是字符串(如
"count": "5"),加配置:new JsonSerializerSettings { NumberHandling = NumberHandling.AllowLeadingAndTrailingWhitespace | NumberHandling.AllowHexSpecifier }
什么时候该放弃强类型,改用 JObject 或 JArray
不是所有 JSON 都适合套类。以下场景硬套 DeserializeObject<t></t> 只会拖慢开发、增加崩溃风险:
- 第三方 API 返回的
data字段是黑盒结构,字段名带时间戳(如"metric_2024_q3")、或根据"type"动态切换内容("type": "user"→ 解成UserDto,"type": "order"→ 解成OrderDto) - 只取日志 JSON 中的
"error.code"和"trace_id"两个字段,其余几十个字段完全无关 - JSON 数组里混着不同类型:
[{"type":"msg","text":"ok"},{"type":"err","code":500}],没法用单一泛型集合承载 - 需要运行时修改字段值再序列化回去(比如打日志前脱敏
obj["user"]["phone"] = "***")
这时候用 JObject.Parse(json) + obj["path"].ToString() 或 (string)obj["path"] 更直接,也更安全。
Newtonsoft.Json 还值得留吗?关键看三点
不是“能不能用”,而是“值不值得为它多扛一个包、多维护一套行为逻辑”:
- 如果你项目已大量使用
JToken做条件分支解析(比如根据token["kind"].ToString()决定后续路径),迁移成本高,可以暂留 - 如果你依赖
TypeNameHandling.Auto反序列化多态类型(比如"$type": "MyApp.User, MyApp"),System.Text.Json 目前仍需手写JsonConverter,Newtonsoft 更省事 - 但新项目、新接口、新 DTO 类型,别再引入它——.NET 6+ 的
System.Text.Json在性能、内存、UTF-8 支持上全面占优,且PropertyNameCaseInsensitive、NumberHandling等开关已补全关键能力
真正容易被忽略的是:Newtonsoft 的 dynamic 解析(比如 var obj = JsonConvert.DeserializeObject<dynamic>(json)</dynamic>)看着方便,实际会让字段拼写错误在运行时才暴露,IDE 不提示、编译不报错、测试难覆盖。










