JsonSerializer.Deserialize是.NET 5+首选,但需严格匹配类型(如int?、PropertyNameCaseInsensitive等);结构多变时用JsonDocument更安全;Newtonsoft.Json行为差异大,需注意大小写、null处理及日期格式;排查错误优先看JsonException的Path和LineNumber。
用 JsonSerializer.Deserialize<t></t> 最直接,但类型必须匹配
反序列化 json 字符串时,jsonserializer.deserialize<t></t> 是 .net 5+ 的首选,快、安全、原生支持。但它对类型定义很“较真”:字段名大小写、nullability、嵌套结构稍有不一致,就可能静默失败或抛 jsonexception。
常见错误现象:JsonException: The JSON value could not be converted to System.Int32 —— 实际是 JSON 里传了 "age": null,而你的 C# 属性是 int Age { get; set; },没加可空标记。
- 用
int?替代int,或加[JsonPropertyName("age")]显式绑定(如果字段名不一致) - 开启
PropertyNameCaseInsensitive = true避免大小写敏感问题 - 嵌套对象属性若为
null,对应 C# 类型也得是可空引用类型(如string?或Person?),否则反序列化会失败
遇到动态 JSON 或字段不确定时,别硬套强类型,改用 JsonDocument
当 API 返回结构多变(比如某些字段有时存在、有时为空字符串、有时是对象)、或者你只取其中一两个字段,强类型定义反而拖慢开发还容易崩。这时候 JsonDocument 更轻量、更可控。
使用场景:解析第三方接口返回的混合结构、做字段存在性判断、提取深层嵌套值而不定义整套类。
-
JsonDocument.Parse(jsonString)不分配对象,内存友好,适合只读访问 - 用
doc.RootElement.GetProperty("data").GetProperty("items")[0].GetString()逐层导航,注意每步都要检查TryGetProperty是否成功,否则抛KeyNotFoundException - 别忘了调用
doc.Dispose()(或用using),否则可能泄漏内存
Newtonsoft.Json 还能用,但要注意默认行为差异
如果你项目还在用 Newtonsoft.Json(即 Json.NET),它兼容性好、灵活性高,但和 System.Text.Json 默认行为差别不小,混用容易踩坑。
典型差异:
-
JsonConvert.DeserializeObject<t></t>默认忽略大小写,而System.Text.Json默认区分(需显式设PropertyNameCaseInsensitive = true) -
Newtonsoft对null值更宽容,比如把null赋给int字段会设为0;System.Text.Json直接报错 - 日期格式:Newtonsoft 默认处理
/Date(123)/,而System.Text.Json只认 ISO 8601,需自定义JsonConverter<datetime></datetime>
反序列化失败时,先看 JsonException 的 Path 和 LineNumber
错误信息里最实用的不是“无法转换”,而是 Path: $.user.profile.age | LineNumber: 42 | BytePositionInLine: 16。它直接定位到 JSON 文本出问题的位置,比对着类一层层猜快得多。
容易被忽略的地方:
- JSON 字符串本身含 BOM(比如从文件读取时用了
File.ReadAllText但没指定Encoding.UTF8),会导致开头出现不可见字符,JsonSerializer解析直接失败 - 前端传来的 JSON 可能带多余逗号(尤其调试时手动拼的),
System.Text.Json严格拒绝,Newtonsoft默认容忍(但建议关掉AllowComments = false避免隐患) - 用
HttpClient.GetStringAsync获取响应后,别直接丢给反序列化——先检查response.IsSuccessStatusCode,否则可能把 HTML 错误页当 JSON 解析


















