如何仅当JSON匹配T类型时使用JsonConvert.DeserializeObject<T>反序列化?
解决Newtonsoft.Json反序列化时强制校验必填字段的问题
默认情况下Newtonsoft.Json的JsonConvert.DeserializeObject<T>会把缺失的字段设为对应类型的default,哪怕是标记为非可空的必填字段,导致空JSON也能反序列化为T的实例。要实现“仅当JSON完全匹配T的必填要求时才返回实例,否则返回null”,可以通过以下两种方式处理:
方式一:手动标记必填字段并捕获异常
给需要校验的必填字段添加[JsonProperty(Required = Required.Always)]属性,然后通过捕获反序列化异常来返回null:
定义目标类型
public record Test( // 标记must为必填字段 [property: JsonProperty(Required = Required.Always)] string must, string? optional );
带校验的反序列化方法
public static Test? DeserializeTest(string json) { try { var settings = new JsonSerializerSettings { // 全局层面强制校验必填项(如果字段没单独标记,也会生效) // Required = Required.Always }; return JsonConvert.DeserializeObject<Test>(json, settings); } catch (JsonSerializationException) { // 当必填字段缺失时抛出异常,直接返回null return null; } }
当输入空JSON{}时,反序列化会抛出JsonSerializationException(提示必填字段must缺失),方法返回null,符合预期。
方式二:自动识别非可空字段为必填(无需手动标记)
如果项目中使用了C# 8+的可空上下文,可以自定义ContractResolver,自动把非可空类型的字段识别为必填字段,避免逐个标记:
自定义ContractResolver
public class RequiredNonNullContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); var memberType = member.GetMemberType(); // 非可空值类型(如int、DateTime)设为必填 if (memberType.IsValueType && Nullable.GetUnderlyingType(memberType) == null) { property.Required = Required.Always; } // 非可空引用类型(如string,在可空上下文下)设为必填 else if (!memberType.IsNullableType()) { property.Required = Required.Always; } return property; } } // 扩展方法:判断类型是否为可空类型 public static class TypeExtensions { public static bool IsNullableType(this Type type) { return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); } }
使用自定义Resolver的反序列化方法
public static Test? DeserializeTest(string json) { try { var settings = new JsonSerializerSettings { ContractResolver = new RequiredNonNullContractResolver() }; return JsonConvert.DeserializeObject<Test>(json, settings); } catch (JsonSerializationException) { return null; } }
这种方式下,无需给Test的must字段加属性,因为它是非可空引用类型,会被自动识别为必填字段,空JSON反序列化时同样会抛出异常并返回null。
额外说明
- 如果需要同时校验JSON中不存在额外字段,可以在
JsonSerializerSettings中设置MissingMemberHandling = MissingMemberHandling.Error,这样JSON有多余字段时也会抛出异常。 - 捕获
JsonSerializationException时可以根据Exception.Message进一步判断错误类型,按需处理。
内容的提问来源于stack exchange,提问作者Sinatr
相关产品推荐
相关产品推荐

