结论是:用 jobject.parse() + selecttoken() 处理复杂嵌套 json 最快最稳,它不依赖预设结构、自动跳过缺失字段、支持 jsonpath 通配与层级穿透,比强类型反序列化更适应真实接口响应。

直接说结论:别急着定义类,用 JObject.Parse() + SelectToken() 是处理复杂嵌套 JSON 最快、最稳的路径。 它不依赖结构预设,能跳过缺失字段,支持通配和层级穿透,比反序列化到强类型对象更适合真实接口响应。
解析前先判断是 JObject 还是 JToken?
绝大多数场景下,你拿到的是一个 JSON 对象(以 { 开头),直接 JObject.Parse(jsonString) 就行。但如果不确定——比如上游可能返回对象、数组甚至纯值("ok" 或 123)——那就统一用 JToken.Parse(jsonString)。
原因很简单:JObject 继承自 JToken,但反过来不成立;JToken.Parse() 能自动识别输入类型并返回对应子类实例(JObject、JArray 或 JValue),避免运行时报 JsonReaderException。
- 如果确定是对象结构,用
JObject更语义清晰,IDE 补全也更友好 - 如果要写通用解析器(比如日志提取、API 响应适配层),一律走
JToken - 别对
JToken直接强转(JObject),要用token as JObject或token.ToObject<jobject>()</jobject>防空指针
用 SelectToken() 精准定位嵌套字段,避开 null 异常
SelectToken() 是你在嵌套深渊里最可靠的探照灯。它支持 JSONPath 语法,比如 "$.data.items[0].product.name",也能用 "$..name" 全局查找所有 name 字段。
关键点在于:它天然容忍路径中断。即使 data 缺失,或 items 是空数组,SelectToken() 返回 null 而不是抛异常——这和直接链式取值 obj["data"]["items"][0]["product"]["name"] 有本质区别。
- 写路径时优先用
$.开头,明确从根开始;省略会默认从当前节点查,容易误匹配 - 数组索引越界(如
[99])不会报错,返回null;但[0]在空数组里也返回null,需额外判空 - 若需多个匹配结果,改用
SelectTokens()(注意复数 s),返回IEnumerable<jtoken></jtoken> - 路径中含点号(
.)或括号的 key,得用单引号包裹,例如"$.info['user.id']"
取值时别硬转,用安全方法防崩溃
很多人写 (string)obj["name"],结果字段一缺就炸。这不是类型转换问题,是设计误用。
JToken 提供了带默认值的取值方法,比强制转换靠谱得多:
-
obj["name"]?.ToString()—— 最简兜底,空则得null -
obj["age"]?.Value<int>() ?? 0</int>—— 安全转基础类型,null或类型不符都 fallback 到0 -
obj.TryGetValue("tags", out JToken tagsToken)—— 类似字典的 Try 模式,推荐用于关键字段校验 - 避免
(int)obj["age"],它在obj["age"]为null或字符串"30"时都会抛异常
遍历嵌套数组和对象时,别用 foreach 直接拆 JToken
JToken 本身不能被 foreach,必须先确认类型再转成具体容器。
常见错误是写 foreach (var item in obj["list"]),结果编译不过或运行时报 InvalidCastException。
- 如果是数组,先
obj["list"] as JArray,再foreach (JToken item in array) - 如果是对象,先
obj["data"] as JObject,再foreach (JProperty prop in obj)或obj.Properties() - 想统一处理任意结构?用
token.Children()获取所有子节点,再按token.Type分支判断(JTokenType.Object/JTokenType.Array/JTokenType.String等) - 需要深度遍历全树?用
token.DescendantsAndSelf(),比手写递归更简洁
真正难的不是语法,而是意识到:JSON 的“结构不确定性”本身就是数据特征,不是缺陷。用 JObject 和 JToken 的核心价值,是把这种不确定性变成可编程的条件分支,而不是靠人工补类、加 try-catch 去硬扛。











