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

如何用Newtonsoft.Json实现C# Record默认参数反序列化同System.Text.Json效果?

解决Newtonsoft.Json反序列化C# Record时默认值不生效的问题

问题背景

我们有一个C# Record,最初仅定义了int no参数,后续迭代新增了带默认值的paramStr参数,定义如下:

record SimpleRecord(int no, string paramStr = "New param that did not existed");

当用仅包含no字段的旧JSON反序列化时:

string jsonText = "{\"no\":10}";
SimpleRecord? parsedJson1 = System.Text.Json.JsonSerializer.Deserialize<SimpleRecord>(jsonText);
SimpleRecord? parsedJson2 = Newtonsoft.Json.JsonConvert.DeserializeObject<SimpleRecord>(jsonText);

System.Text.Json能正确为paramStr赋予默认值,但Newtonsoft.Json得到的paramStr为null。现有项目基于Newtonsoft.Json,不想重构,需要实现与System.Text.Json一致的反序列化效果。

解决方案

方法1:给参数添加特性指定默认值处理

直接在Record的paramStr参数上添加[JsonProperty]和[DefaultValue]特性,配置默认值填充规则:

record SimpleRecord(
    int no, 
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] 
    [DefaultValue("New param that did not existed")] 
    string paramStr = "New param that did not existed"
);

这样Newtonsoft.Json在反序列化时,会自动为缺失的paramStr字段填充指定的默认值。

方法2:自定义ContractResolver全局配置

如果不想逐个修改Record,可以自定义一个ContractResolver,让它自动识别Record可选参数的默认值并应用填充:

public class RecordDefaultValueContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        
        // 检查当前属性是否属于Record类型,且对应构造参数有默认值
        if (member is PropertyInfo prop && prop.DeclaringType.IsRecord())
        {
            var ctor = prop.DeclaringType.GetConstructors()
                .FirstOrDefault(c => c.GetParameters().Any(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase)));
            
            var param = ctor?.GetParameters().FirstOrDefault(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
            if (param != null && param.HasDefaultValue)
            {
                property.DefaultValue = param.DefaultValue;
                property.DefaultValueHandling = DefaultValueHandling.Populate;
            }
        }
        
        return property;
    }
}

使用时,在反序列化配置中指定这个Resolver:

var settings = new JsonSerializerSettings
{
    ContractResolver = new RecordDefaultValueContractResolver()
};
SimpleRecord? parsedJson2 = JsonConvert.DeserializeObject<SimpleRecord>(jsonText, settings);

也可以设置为全局默认配置,避免每次反序列化都重复指定:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
    ContractResolver = new RecordDefaultValueContractResolver()
};

方法3:显式指定构造器(单个Record场景)

对于单个Record,也可以显式定义构造器,确保Newtonsoft.Json在反序列化时使用带默认值的参数:

record SimpleRecord
{
    public int No { get; init; }
    public string ParamStr { get; init; }

    public SimpleRecord(int no, string paramStr = "New param that did not existed")
    {
        No = no;
        ParamStr = paramStr;
    }
}

这种方式需要把Record从位置参数语法改为显式属性+构造器的形式,适合不需要大量修改的场景。

内容的提问来源于stack exchange,提问作者Audrius Gailius

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 05:15:37