使用Json.Net反序列化后如何获取所有未匹配键与缺失字段?
解决方案
你不需要完全自定义JsonConverter,搭配Newtonsoft.Json自带的错误回调和JObject预解析即可实现两类不匹配项的检查,实现成本极低。
第一步:配置反序列化参数捕获JSON多余键
通过MissingMemberHandling.Error配置触发未匹配键的错误,再通过自定义Error回调收集日志,不会中断反序列化流程:
var deserializeSettings = new JsonSerializerSettings { // 遇到结构体未定义的JSON键时抛出错误 MissingMemberHandling = MissingMemberHandling.Error, // 全局错误处理,收集多余键日志 Error = (sender, args) => { if (args.ErrorContext.Error is JsonSerializationException) { var parentType = args.CurrentObject.GetType().Name; var extraKey = args.ErrorContext.Path; // 输出你需要的日志格式 Console.WriteLine($"[Error][{parentType}::{extraKey} key not exist in struct]"); // 标记错误已处理,继续反序列化流程 args.ErrorContext.Handled = true; } } };
第二步:预解析JObject检查JSON缺失字段
先把JSON字符串解析为JObject,递归对比目标结构体的所有字段和JObject的键,收集缺失字段的日志:
using System.Reflection; using Newtonsoft.Json.Linq; public static List<string> GetMissingFieldLogs(JObject jObj, Type targetType, string parentPath = "") { var logs = new List<string>(); // 获取当前类型的所有公开实例字段 var fields = targetType.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (var field in fields) { string currentPath = string.IsNullOrEmpty(parentPath) ? $"{targetType.Name}::{field.Name}" : $"{parentPath}::{field.Name}"; // 检查JSON中是否存在对应键 if (!jObj.TryGetValue(field.Name, out JToken value)) { logs.Add($"[Error][{currentPath} field not exist in json string]"); continue; } // 嵌套结构体递归检查 var fieldType = field.FieldType; if (fieldType.IsValueType && !fieldType.IsPrimitive && !fieldType.IsEnum && fieldType != typeof(decimal)) { if (value is JObject childJObj) { logs.AddRange(GetMissingFieldLogs(childJObj, fieldType, currentPath)); } } } return logs; }
第三步:组合调用
// 你的JSON字符串 string jsonStr = @"{ ""Hp"": 100, ""PlayerInfo"": { ""Atk"": 10, ""Def"": 20 }, ""Mp"": 100 }"; // 1. 预解析JObject,检查缺失字段 JObject jObj = JObject.Parse(jsonStr); var missingLogs = GetMissingFieldLogs(jObj, typeof(CharaData)); foreach (var log in missingLogs) { Console.WriteLine(log); } // 2. 反序列化,检查多余键 CharaData data = jObj.ToObject<CharaData>(JsonSerializer.Create(deserializeSettings));
运行输出
完全符合你要求的日志格式:
[Error][CharaData::PlayerInfo::Spd field not exist in json string] [Error][CharaData::Mp key not exist in struct]
补充说明
- 如果你的字段加了
[JsonProperty("自定义别名")]属性,只需要在GetMissingFieldLogs方法中先获取字段的JsonPropertyAttribute的Name值作为键名对比即可。 - 如果需要支持数组、列表类型的检查,扩展
GetMissingFieldLogs的递归逻辑即可。 - 如果追求更高性能,不想两次解析JSON,可以自定义
JsonConverter边反序列化边做两类检查,实现逻辑和上面的思路一致。
内容的提问来源于stack exchange,提问作者HelloWorld
相关产品推荐
相关产品推荐

