【问题标题】:Deserialization of self-referencing properties does not work自引用属性的反序列化不起作用
【发布时间】:2017-07-27 01:46:33
【问题描述】:

我有这个对象,它的 Parent 属性引用了另一个相同类型的对象:

[JsonObject(IsReference = true)]
class Group
{
    public string Name { get; set; }

    public Group(string name)
    {
        Name = name;
        Children = new List<Group>();
    }

    public IList<Group> Children { get; set; }

    public Group Parent { get; set; }

    public void AddChild(Group child)
    {
        child.Parent = this;
        Children.Add(child);
    }
}

序列化工作正常,结果 json 看起来像这样:

{
  "$id": "1",
  "Name": "Parent",
  "Children": [
    {
      "$id": "2",
      "Name": "Child",
      "Children": [],
      "Parent": {
        "$ref": "1"
      }
    }
  ],
  "Parent": null
}

但是反序列化不起作用。 Parent 属性返回 null。

一个测试看起来像这样:

[Test]
public void Test()
{
    var child = new Group("Child");
    var parent = new Group("Parent");
    parent.AddChild(child);

    var json = JsonConvert.SerializeObject(parent, Formatting.Indented);
    Debug.WriteLine(json);

    var deserializedParent = (Group) JsonConvert.DeserializeObject(json, typeof(Group));
    Assert.IsNotNull(deserializedParent.Children.First().Parent);
}

我做错了什么?任何帮助表示赞赏!

【问题讨论】:

    标签: json.net


    【解决方案1】:

    要扩展 James's answer,您可以通过为 Json.Net 提供无参数(默认)构造函数来解决此问题。如果你愿意,它可以是私有的,只要你也用[JsonConstructor] 属性标记它。

    [JsonObject(IsReference = true)]
    class Group
    {
        ...
    
        [JsonConstructor]
        private Group()
        {
        }
    
        public Group(string name)
        {
            Name = name;
            Children = new List<Group>();
        }
    
        ...
    }
    

    这种安排允许 Json.Net 无需预先提供所有信息即可创建对象;然后它可以使用公共属性来填充之后的内容。

    小提琴:https://dotnetfiddle.net/QfqV43

    【讨论】:

      【解决方案2】:

      另一种方式,我发现,非常固执是创建一个两阶段反序列化,
      正如我在下面描述的Deserializing Circular References by Two-Phase deserialization

      一般来说,我创建了两个 IContractResolver,一个用于仅反序列化 Constructor 的属性(如果它有参数)。

      在第二阶段,我使用常规 ContractResolver 填充对象。

      【讨论】:

        【解决方案3】:

        使用引用不适用于只有带有参数的构造函数的对象。

        Json.NET 必须在创建父对象之前反序列化所有子值,它需要将这些值传递给构造函数,因此没有有效的父引用可以分配给子对象。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-07-11
          • 1970-01-01
          • 1970-01-01
          • 2018-04-21
          • 1970-01-01
          相关资源
          最近更新 更多