Unity JsonUtility/LitJson解析JSON遇KeyNotFoundException及嵌套取值问题
问题根因与解决方案
一、报错代码的核心问题
你遇到的KeyNotFoundException,本质是对JSON的两个基础特性不熟悉导致的:
- JSON键名是严格大小写敏感的
LitJson内部把JSON对象映射为严格区分大小写的字典结构,必须和JSON原文的键名字符完全匹配才能访问到值。你提供的JSON原文中,data节点下的键是otherInfo(Info的首字母I为大写),但代码里写的是otherinfo(info全小写),两个字符串不完全相等,自然找不到对应键值。
你第一个示例能正常运行,是因为代码里访问的stats、kills键名和JSON原文完全大小写一致,和解析逻辑本身没有关系。 - JSON容器的访问规则差异
JSON只有两种核心容器结构,访问逻辑完全不同:- 大括号
{}包裹的对象结构:通过字符串键名访问成员 - 中括号
[]包裹的数组结构:通过从0开始的整数索引访问成员,不存在字符串键
- 大括号
二、LitJson 场景下的可扩展实现
基础修正:单键值正确读取
修正键名大小写匹配问题后,即可正常读取otherInfo字段:
JsonData jsonData = JsonMapper.ToObject(jsonString); JsonData dataObj = jsonData["data"]; // 严格匹配JSON原文的键名大小写 int otherInfo = int.Parse(dataObj["otherInfo"].ToString()); Debug.Log(otherInfo);
小技巧:LitJson的对象类型JsonData提供了
ContainsKey方法,取值前可以先判断目标键是否存在,避免键名不匹配时直接抛出异常导致程序崩溃。
// 安全判断键存在再取值的写法 if (dataObj.ContainsKey("otherInfo")) { int otherInfo = int.Parse(dataObj["otherInfo"].ToString()); }
可扩展读取任意数量的玩家数据
对于scoreboard这种数组结构,LitJson会自动将其识别为带整数索引、有Count属性的集合,不管数组内有多少个玩家条目,都可以通过遍历的方式读取,不需要写死固定数量的取值逻辑:
JsonData scoreboardArray = dataObj["scoreboard"]; // 遍历所有玩家条目,覆盖任意数量的玩家 for (int i = 0; i < scoreboardArray.Count; i++) { JsonData currentPlayer = scoreboardArray[i]; // 读取玩家基础字段 string playerName = currentPlayer["player"].ToString(); int playerScore = int.Parse(currentPlayer["score"].ToString()); // 读取嵌套的pdata数据 JsonData pdata = currentPlayer["pdata"]; int pdataValueA = int.Parse(pdata["a"].ToString()); int pdataValueB = int.Parse(pdata["b"].ToString()); // 在此处可自定义逻辑存储读取到的玩家数据 Debug.Log($"玩家{playerName} 分数{playerScore} pdata值:a={pdataValueA}, b={pdataValueB}"); }
三、可迁移到JsonUtility的适配方案
如果后续需要从LitJson切换到Unity原生的JsonUtility,只需要按照JSON结构定义对应的可序列化类即可,核心要求同样是字段名和JSON键名严格大小写匹配:
- 按照JSON层级定义对应数据结构:
[System.Serializable] public class PData { public int a; public int b; } [System.Serializable] public class PlayerEntry { public string player; public int score; public PData pdata; } [System.Serializable] public class DataNode { public int otherInfo; public List<PlayerEntry> scoreboard; public int otherInfo2; } [System.Serializable] public class RootStructure { public DataNode data; }
- 反序列化与读取逻辑:
RootStructure root = JsonUtility.FromJson<RootStructure>(jsonString); // 直接读取otherInfo字段 int info = root.data.otherInfo; // 遍历任意数量的玩家条目,无需调整代码适配条目数量变化 foreach (var player in root.data.scoreboard) { string name = player.player; int score = player.score; int pA = player.pdata.a; int pB = player.pdata.b; }
内容的提问来源于stack exchange,提问作者coldchickens
相关产品推荐
相关产品推荐

