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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:22:03