Json.net序列化程序正在错误处理`PreserveReferencesHandling`和`ReferenceLoopHandling`

时间:2018-09-19 15:02:49

标签: c# json serialization json.net

考虑以下模型

public class Root
{
    public static int latestID = 0;
    public Root()
    {
        SpecificBranchA = new A(this) { BranchID = latestID + 1 };
    }
    public A SpecificBranchA { get; }
}
public class A
{
    public Root Owner { get; }
    public int BranchID { get; set; }
    [JsonConstructor]
    public A(Root owner)
    {
        Owner = owner;
    }
    public List<B> Children { get; } = new List<B>();
}
public class B
{
    public A Owner { get; }
    public int LeafID { get; set; }
    [JsonConstructor]
    public B(A owner)
    {
        Owner = owner;
    }
}

和此示例实例:

var root = new Root();
root.Obj.Children.Add(new B(root.Obj) { LeafID = 1 });
root.Obj.Children.Add(new B(root.Obj) { LeafID = 2 });
root.Obj.Children.Add(new B(root.Obj) { LeafID = 3 });

当使用这些设置进行序列化时,这会给出错误的json:

var res = JsonConvert.SerializeObject(root, new JsonSerializerSettings()
{                   
    PreserveReferencesHandling = PreserveReferencesHandling.All,
    ReferenceLoopHandling = ReferenceLoopHandling.Serialize,

    TypeNameHandling = TypeNameHandling.Objects, //only for reading simplicity
    Formatting = Formatting.Indented //only for reading simplicity
});

结果:

{
  "$id": "1",
  "$type": "TestJSONSerializer.Root, TestJSONSerializer",
  "SpecificBranchA": {
    "$type": "TestJSONSerializer.A, TestJSONSerializer",
    "Owner": {
      "$ref": "1"
    },
    "BranchID": 1,
    "Children": [
      {
        "$id": "2",
        "$type": "TestJSONSerializer.B, TestJSONSerializer",
        "Owner": {
          "$id": "3",
          "$type": "TestJSONSerializer.A, TestJSONSerializer",
          "Owner": {
            "$ref": "1"
          },
          "BranchID": 1,
          "Children": [
            {
              "$ref": "2"
            },
            {
              "$id": "4",
              "$type": "TestJSONSerializer.B, TestJSONSerializer",
              "Owner": {
                "$ref": "3"
              },
              "LeafID": 2
            },
            {
              "$id": "5",
              "$type": "TestJSONSerializer.B, TestJSONSerializer",
              "Owner": {
                "$ref": "3"
              },
              "LeafID": 3
            }
          ]
        },
        "LeafID": 1
      },
      {
        "$ref": "4"
      },
      {
        "$ref": "5"
      }
    ]
  }
}

在这里您可以注意到,在A的构造函数中存储在属性A.SpecificBranchA中的对象创建了两次序列化,并且出现了一些奇怪的嵌套行为。

但是当单独序列化A对象时,您不会得到这种行为。

(是的,当您致电JsonConvert.SerializeObject(root.SpecificBranchA,...)时不会发生这种情况)

它看起来像是Json.net中的错误,但我不确定自己做错了什么

1 个答案:

答案 0 :(得分:1)

所以看来我不是按照Json.net的设计以错误的方式做事(感谢@dbc的评论)

我稍微改变了模型,一切正常

在根类中,我将属性SpecificBranchA的定义更改为以下内容

[JsonProperty]
public A SpecificBranchA { get; private set; }

,序列化将按预期进行。 因此,我认为任何包含带有引用循环的对象的属性,都必须具有一个setter(即使是私有的)并标有[JsonProperty]。如果缺少任何一个,则序列化会得到错误的行为。


@dbc发布的

相关问题