如何用C#编写基于Newtonsoft.Json的通用JSON更新函数
通用JSON路径更新函数实现(基于Newtonsoft.Json)
我完全懂你这种重复写嵌套路径访问的痛苦——每次为不同的JSON节点写单独的修改逻辑,不仅冗余还容易出错。下面是一个实用的通用函数,专门解决这个问题,支持用字符串数组传递路径,动态定位并修改目标值:
核心实现代码
using Newtonsoft.Json.Linq; using System; public static class JsonHelper { public static void UpdateJsonValue(JObject rootJsonObject, string[] valuePath, object newValue) { // 基础参数校验 if (rootJsonObject == null) throw new ArgumentNullException(nameof(rootJsonObject)); if (valuePath == null || valuePath.Length == 0) throw new ArgumentException("JSON路径不能为空", nameof(valuePath)); JToken currentNode = rootJsonObject; // 遍历路径数组,逐步定位到目标节点 for (int i = 0; i < valuePath.Length; i++) { string currentKey = valuePath[i]; // 到达路径最后一个节点,执行赋值操作 if (i == valuePath.Length - 1) { // 自动适配值的类型,转换成对应的JToken currentNode[currentKey] = JToken.FromObject(newValue); return; } // 处理中间节点:如果节点不存在或者不是对象类型,自动创建JObject(可根据需求调整) if (currentNode[currentKey] == null || currentNode[currentKey].Type != JTokenType.Object) { currentNode[currentKey] = new JObject(); } // 移动到下一层节点 currentNode = currentNode[currentKey]; } } }
关键特性说明
- 动态路径遍历:不需要硬编码
["Object1"]["Object2"]这种嵌套访问,直接用字符串数组传递路径即可 - 自动创建中间节点:如果路径中的某个中间对象不存在(比如你要更新
Object1.Object3.key但Object3还没创建),函数会自动生成对应的JObject,避免空引用异常 - 类型自动适配:通过
JToken.FromObject()可以将任意类型的newValue(字符串、数字、布尔值甚至自定义对象)转换成JSON支持的格式
使用示例
假设你有以下原始JSON:
{ "UserInfo": { "Profile": { "Nickname": "OldNickname", "Age": 25 } } }
调用函数修改值的方式如下:
// 1. 解析JSON字符串到JObject string originalJson = "{\"UserInfo\":{\"Profile\":{\"Nickname\":\"OldNickname\",\"Age\":25}}}"; JObject jsonObj = JObject.Parse(originalJson); // 2. 定义要修改的路径和新值 string[] nicknamePath = { "UserInfo", "Profile", "Nickname" }; JsonHelper.UpdateJsonValue(jsonObj, nicknamePath, "NewNickname"); string[] agePath = { "UserInfo", "Profile", "Age" }; JsonHelper.UpdateJsonValue(jsonObj, agePath, 26); // 3. 输出修改后的JSON Console.WriteLine(jsonObj.ToString(Newtonsoft.Json.Formatting.Indented));
执行后输出的JSON会变成:
{ "UserInfo": { "Profile": { "Nickname": "NewNickname", "Age": 26 } } }
扩展场景:支持数组索引
如果你的JSON路径包含数组(比如要修改UserInfo.Addresses[0].City),可以给函数添加数组处理逻辑:
// 在循环中替换中间节点的处理逻辑 if (currentNode.Type == JTokenType.Array && int.TryParse(currentKey, out int arrayIndex)) { JArray targetArray = (JArray)currentNode; // 如果索引超出数组长度,自动扩容(可选,也可以抛出异常) while (targetArray.Count <= arrayIndex) { targetArray.Add(new JObject()); } currentNode = targetArray[arrayIndex]; } else { // 原有的对象节点处理逻辑 if (currentNode[currentKey] == null || currentNode[currentKey].Type != JTokenType.Object) { currentNode[currentKey] = new JObject(); } currentNode = currentNode[currentKey]; }
这样就能支持类似{ "UserInfo", "Addresses", "0", "City" }这种包含数组索引的路径了。
内容的提问来源于stack exchange,提问作者Felipe Centeno
相关产品推荐
相关产品推荐

