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);
为什么这个方案有效?
- 列表/集合处理:通过ContractResolver为集合类型单独指定
Replace模式,反序列化时会直接用JSON中的集合实例替换构造函数初始化的集合,不会出现合并元素的情况; - null属性处理:设置
NullValueHandling.Include确保JSON中的null值会被主动赋值给对应属性,覆盖构造函数中初始化的非null实例; - 无侵入性:不需要修改现有类的构造函数,也不需要给任何属性添加
JsonProperty之类的特性,完全符合你的需求; - 默认初始化保留:对于那些你没有修改(也没有出现在JSON中)的属性,反序列化时会保留构造函数初始化的值,满足“创建新实例时仍需初始化”的要求。
用这个方案运行你的测试用例,就能得到和序列化前完全一致的实例:
deserialized.ListProperty.Count会是1(只有元素3);deserialized.APropertyToBeNull和deserialized.BPropertyToBeNull会是null;- 所有未修改的属性会保持构造函数初始化的状态。
内容的提问来源于stack exchange,提问作者700z
相关产品推荐
相关产品推荐

