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

使用Newtonsoft.Json序列化反序列化后出现数据丢失问题求助

Newtonsoft.Json序列化反序列化后数据丢失原因分析

我在使用Newtonsoft.Json时遇到序列化反序列化后数据丢失的问题,复现代码如下:

internal class Program
{
    private static JsonSerializerSettings Setting = new Newtonsoft.Json.JsonSerializerSettings()
    {
        PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    };
    static void Main(string[] args)
    {
        var script = new SubClass();
        script.Param.Add(new Parameter()
        {
            msg = "I will die"
        });
        var obj = new Class();
        obj.subObj = script;

        string json;
        string json2;
        json = JsonConvert.SerializeObject(obj, Setting);
        Console.WriteLine("before:");
        Console.WriteLine(json);
        obj = Newtonsoft.Json.JsonConvert.DeserializeObject<Class>(json, Setting);
        json2 = JsonConvert.SerializeObject(obj, Setting);
        Console.WriteLine("after:");
        Console.WriteLine(json2);
    }

    public class Class
    {
        public IEnumerable<Parameter> parameters => subObj?.parameters();
        public SubClass subObj { get; set; }
    }

    public class Parameter
    {
        public string msg { get; set; }
    }
    public class SubClass
    {
        public List<Parameter> Param { get; set; } = new List<Parameter>();

        public IEnumerable<Parameter> parameters()
        {
            return Param;
        }
    }
}

运行后两次序列化结果差异明显:
第一次序列化(反序列化前):

{"$id":"1","parameters":[{"$id":"2","msg":"I will die"}],"subObj":{"$id":"3","Param":[{"$ref":"2"}]}}

第二次序列化(反序列化后):

{"$id":"1","parameters":[null],"subObj":{"$id":"2","Param":[null]}}

删除Class类的parameters属性后,问题消失,运行结果恢复正常。


问题根源

这个问题的核心是**PreserveReferencesHandling.Objects设置与只读计算属性的序列化顺序冲突**:

  1. 序列化时的引用跟踪:
    启用PreserveReferencesHandling.Objects后,Json.NET会为每个唯一对象分配$id,重复引用的对象会用$ref指向对应$id。第一次序列化时,Class.parameters返回的是subObj.Param中的同一个Parameter实例,所以Json.NET给这个实例分配$id=2,subObj.Param里的元素用$ref=2引用,序列化结果正常。

  2. 反序列化时的顺序问题:
    Json.NET反序列化是按照JSON属性的顺序处理的:

    • 先处理Class的parameters属性,遇到{"$ref":"2"}时,$id=2对应的Parameter实例还未被创建(因为它在subObj.Param里,而subObj属性在JSON中排在parameters之后,还未处理)。
    • Json.NET无法解析未创建对象的引用,只能用null填充。
    • 后续处理subObj的Param属性时,再次遇到{"$ref":"2"},此时对象缓存中仍然没有$id=2的实例,只能再次填充null。
  3. 只读计算属性的影响:
    Class.parameters是一个只读的计算属性(只有get逻辑,没有setter),Json.NET反序列化时无法将JSON值赋值给它,但仍会尝试解析对应的JSON数据。这个无效的解析过程破坏了引用跟踪的逻辑,最终导致两次序列化后数据丢失。


解决思路

  • 如果你需要保留parameters属性,可以给它添加[JsonIgnore]特性,让Json.NET序列化和反序列化时忽略这个属性,避免干扰引用跟踪。
  • 调整JSON属性的序列化顺序,让subObj属性先于parameters被处理(可以用[JsonProperty(Order = -1)]给subObj设置更高的优先级)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:01:42