在C#中计算两个JSON对象的差异并生成指定结构的结果JSON
在C#中计算两个JSON对象的差异并生成指定结构的结果JSON
我明白你想要的是和原JSON结构对齐的差异结果,而不是JsonPatch那种操作指令式的输出。用Json.NET(Newtonsoft.Json)来实现这个需求会很灵活,下面我给你写个实用的递归对比方法,完全符合你的要求:
实现思路
核心逻辑是递归遍历新旧两个JSON对象的所有属性,按照规则生成差异结构:
- 新增属性:原对象没有、新对象有的,直接保留新对象的值
- 删除属性:原对象有、新对象没有的,设为空字符串
- 修改属性:两者都有但值不同的,保留新对象的值;如果是嵌套对象,只保留嵌套结构里有变化的属性
- 无变化的属性:直接忽略,不加入结果
代码实现
首先确保你已经安装了Newtonsoft.Json NuGet包,然后可以用下面的代码:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public static class JsonDiffHelper { public static JObject GenerateStructuredDiff(JObject oldObj, JObject newObj) { var diffObj = new JObject(); // 遍历新对象的所有属性,处理新增和修改的情况 foreach (var prop in newObj.Properties()) { var oldProp = oldObj.Property(prop.Name); if (oldProp == null) { // 新增属性:直接加入结果 diffObj.Add(prop.Name, prop.Value.DeepClone()); } else { if (prop.Value.Type == JTokenType.Object && oldProp.Value.Type == JTokenType.Object) { // 嵌套对象:递归处理差异 var nestedDiff = GenerateStructuredDiff((JObject)oldProp.Value, (JObject)prop.Value); if (nestedDiff.HasValues) { diffObj.Add(prop.Name, nestedDiff); } } else if (!JToken.DeepEquals(prop.Value, oldProp.Value)) { // 值不同的属性:保留新值 diffObj.Add(prop.Name, prop.Value.DeepClone()); } } } // 遍历原对象的属性,处理删除的情况 foreach (var prop in oldObj.Properties()) { if (newObj.Property(prop.Name) == null) { // 删除属性:设为空字符串 diffObj.Add(prop.Name, string.Empty); } } return diffObj; } } // 测试示例 class Program { static void Main() { string obj1Json = @" { ""id"": ""94774"", ""name"": ""testName"", ""colour"": ""red"", ""date"": { ""year"": 2021, ""month"": 10, ""day"": 21 } }"; string obj2Json = @" { ""id"": ""86970"", ""name"": ""testName"", ""foo"": ""bar"", ""date"": { ""year"": 2022, ""month"": 10, ""day"": 21 } }"; JObject oldObj = JObject.Parse(obj1Json); JObject newObj = JObject.Parse(obj2Json); JObject diffResult = JsonDiffHelper.GenerateStructuredDiff(oldObj, newObj); Console.WriteLine(diffResult.ToString(Formatting.Indented)); } }
运行结果
执行上面的代码,输出的结果和你期望的完全一致:
{ "id": "86970", "foo": "bar", "date": { "year": 2022 }, "colour": "" }
补充说明
- 如果你的项目用的是
System.Text.Json,也可以用类似的递归逻辑,通过JsonElement来遍历属性,只是API会略有不同 - 这个方法支持多层嵌套的JSON结构,不管嵌套多少层,都会只保留有变化的部分
- 对于数组类型的属性,当前代码会直接对比整个数组是否相等,如果需要更细粒度的数组差异,可以在方法里添加数组的处理逻辑
备注:内容来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

