Newtonsoft Json含列表快速访问属性类的反序列化重复问题求助
问题
父类包含子POCO集合,同时定义了一个快速访问集合首个成员的只读属性FirstChild;子POCO类型自身也包含一个子集合。使用Json.NET进行往返序列化时,第一个子对象的集合内容会重复,反序列化后deserializedParent.Children[0].Children.Count实际值为2,预期值为1。
最小可复现代例
using System; using Newtonsoft.Json; using System.Collections.Generic; using System.Linq; namespace MyApp { internal class Program { static void Main(string[] args) { var parent = new Parent { Children = new List<Child> { new Child { Children = new List<GrandChild> { new GrandChild { Value = "I am a grand child" }, } }, new Child(), } }; var serializedParent = JsonConvert.SerializeObject(parent); var deserializedParent = JsonConvert.DeserializeObject<Parent>(serializedParent); // Expected: 1, Actual: 2 Console.WriteLine(deserializedParent.Children[0].Children.Count); } } public class Parent { public List<Child> Children { get; set; } = new List<Child>(); public Child FirstChild => Children.First(); } public class Child { public List<GrandChild> Children { get; set; } = new List<GrandChild>(); } public class GrandChild { public string Value { get; set; } } }
原因
Json.NET默认会序列化所有公共属性,包括FirstChild这个只读属性。序列化时,FirstChild指向的是Children[0],因此生成的JSON中会同时包含Children数组和FirstChild对象;反序列化时,Json.NET会先将FirstChild的内容反序列化为一个新的Child实例,之后反序列化Children数组时,又会把第一个Child的内容合并到之前创建的实例中——这就导致Children[0].Children集合被重复添加了一次元素。
解决方案
方案1:标记FirstChild为不序列化
给FirstChild属性添加[JsonIgnore]特性,让Json.NET序列化时忽略该属性:
public class Parent { public List<Child> Children { get; set; } = new List<Child>(); [JsonIgnore] public Child FirstChild => Children.First(); }
方案2:全局配置忽略只读属性
如果存在多个类似的只读属性,可以通过全局配置让Json.NET忽略所有无setter的公共属性:
var settings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver { IgnoreReadOnlyProperties = true } }; var serializedParent = JsonConvert.SerializeObject(parent, settings); var deserializedParent = JsonConvert.DeserializeObject<Parent>(serializedParent, settings);
方案3:将FirstChild改为方法(不推荐)
由于Json.NET默认不会序列化方法,将只读属性改为方法也能避免该问题,但这种方式会改变原有的API设计:
public class Parent { public List<Child> Children { get; set; } = new List<Child>(); public Child GetFirstChild() => Children.First(); }
内容的提问来源于stack exchange,提问作者Bohdan
相关产品推荐
相关产品推荐

