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

JSON.NET反序列化:保留序列化状态且不移除构造函数初始化

解决方案:自定义ContractResolver实现两全的反序列化行为

我完全理解你的痛点——既要保留构造函数里的属性初始化逻辑(确保新实例创建时的默认状态),又要让反序列化完全还原序列化前的实例状态,包括null属性和替换后的列表,确实是Newtonsoft.Json默认设置下的矛盾点。

接下来直接上可行的方案,不需要修改现有类的任何代码,也不用加特性:

自定义ContractResolver解决核心矛盾

我们可以通过自定义ContractResolver,针对不同类型的属性设置差异化的反序列化规则:

  • 对列表/集合类型属性强制使用ObjectCreationHandling.Replace,确保反序列化时直接替换整个集合,而不是合并到构造函数初始化的集合中;
  • 对所有属性确保JSON中的null值会覆盖构造函数初始化的实例,同时保留未在JSON中出现的属性的构造函数初始化值。

实现自定义ContractResolver

public class CustomContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        // 针对所有实现IList的泛型集合,设置替换模式
        if (typeof(IList).IsAssignableFrom(property.PropertyType) && property.PropertyType.IsGenericType)
        {
            property.ObjectCreationHandling = ObjectCreationHandling.Replace;
        }

        // 确保JSON中的null值会赋值给属性,覆盖构造函数的初始化
        property.NullValueHandling = NullValueHandling.Include;
        // 确保即使属性值是默认值(比如null)也会被处理
        property.DefaultValueHandling = DefaultValueHandling.Include;

        return property;
    }
}

使用方式

在反序列化时,将这个自定义解析器传入JsonSerializerSettings即可:

var settings = new JsonSerializerSettings
{
    ContractResolver = new CustomContractResolver(),
    // 这里ObjectCreationHandling用Auto即可,因为我们已经为集合单独设置了Replace
    ObjectCreationHandling = ObjectCreationHandling.Auto
};

var deserialized = JsonConvert.DeserializeObject<ExampleClass>(raw, settings);

为什么这个方案有效?

  1. 列表/集合处理:通过ContractResolver为集合类型单独指定Replace模式,反序列化时会直接用JSON中的集合实例替换构造函数初始化的集合,不会出现合并元素的情况;
  2. null属性处理:设置NullValueHandling.Include确保JSON中的null值会被主动赋值给对应属性,覆盖构造函数中初始化的非null实例;
  3. 无侵入性:不需要修改现有类的构造函数,也不需要给任何属性添加JsonProperty之类的特性,完全符合你的需求;
  4. 默认初始化保留:对于那些你没有修改(也没有出现在JSON中)的属性,反序列化时会保留构造函数初始化的值,满足“创建新实例时仍需初始化”的要求。

用这个方案运行你的测试用例,就能得到和序列化前完全一致的实例:

  • deserialized.ListProperty.Count会是1(只有元素3);
  • deserialized.APropertyToBeNull和deserialized.BPropertyToBeNull会是null;
  • 所有未修改的属性会保持构造函数初始化的状态。

内容的提问来源于stack exchange,提问作者700z

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:44:36