如何使用Newtonsoft.Json修改JObject中的嵌套属性值?
问题描述
我有如下结构的config.json:
{ "Field": { "FieldKey1": "FieldValue1", "FieldKey2": "FieldValue2" }, "List": [ "ListEntry1", "ListEntry2" ], "UnnestedKey": "UnnestedValue" }
通过以下代码可以正常读取嵌套值:
var x = await ConfigUtils.Get(configPath, "Field.FieldKey1"); Console.WriteLine(x.ToString());
对应的Get方法实现:
using Newtonsoft.Json; public static async Task<JToken> Get(string filePath, string key) { JObject jObject = await GetJObject(filePath); return jObject.SelectToken(key) ?? throw new KeyNotFoundException($"Key \"{key}\" doesn't exist in {filePath}."); } private static async Task<JObject> GetJObject(string filePath) { string jsonString = await File.ReadAllTextAsync(filePath); JObject jObject = JObject.Parse(jsonString); return jObject; }
这段代码能正确输出FieldValue1。
但调用以下代码修改嵌套值时出现问题:
await ConfigUtils.UpdateValue(configPath, "Field.FieldKey1", "NewValue");
对应的UpdateValue方法实现:
using Newtonsoft.Json; public static async Task UpdateValue(string filePath, string key, string value) { JObject jObject = await GetJObject(filePath); jObject.AddOrReplace(key, value); await WriteJObject(jObject, filePath); }
执行后会新增一个名为Field.FieldKey1的顶级键,而非修改Field下的FieldKey1的值。
我知道需要用jObject.SelectToken(key)来定位嵌套节点,但不清楚后续如何修改,对JToken、JProperty、JObject的使用感到困惑,请问该如何修改UpdateValue方法以支持嵌套值的修改?
解决方案
问题出在AddOrReplace方法会把带点的键当作完整的顶级键名,而非解析为嵌套路径。要修改嵌套值,需先通过SelectToken定位到目标节点,再替换其值。
修改后的UpdateValue方法如下:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public static async Task UpdateValue(string filePath, string key, string value) { JObject jObject = await GetJObject(filePath); // 定位到目标嵌套节点 JToken targetToken = jObject.SelectToken(key); if (targetToken == null) { throw new KeyNotFoundException($"Key \"{key}\" doesn't exist in {filePath}."); } // 根据目标节点类型处理值替换 if (targetToken is JProperty property) { // 若为属性节点,直接替换其值 property.Value = value; } else { // 若为其他类型节点(如JValue),替换整个节点内容 targetToken.Replace(JToken.FromObject(value)); } await WriteJObject(jObject, filePath); } // 补充WriteJObject方法实现(若之前未定义) private static async Task WriteJObject(JObject jObject, string filePath) { string updatedJson = jObject.ToString(Formatting.Indented); await File.WriteAllTextAsync(filePath, updatedJson); }
关键说明
- 用SelectToken定位节点:和读取逻辑一致,通过
SelectToken(key)找到嵌套目标节点,避免将带点的键当作单一顶级键。 - 区分节点类型处理:针对
JProperty(键值对属性)直接修改Value;针对JValue等节点使用Replace方法替换内容。 - 异常处理:若指定键路径不存在,抛出对应异常,和读取逻辑保持统一。
修改后,调用UpdateValue(configPath, "Field.FieldKey1", "NewValue")即可正确修改Field下FieldKey1的值,不会新增顶级键。
内容的提问来源于stack exchange,提问作者user21526533
相关产品推荐
相关产品推荐

