You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅当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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:47:10