【问题标题】:Deserializing json tree structure and setting parents反序列化 json 树结构并设置父级
【发布时间】:2016-05-27 11:26:31
【问题描述】:

这似乎是一个非常基本的问题,但我正在努力寻找一个优雅的解决方案。我有一个用来构建树结构的 Node 类。然后使用JsonConvert.SerializeObject(..) 将其序列化为 JSON。为了防止序列化时出现循环引用,我在 Parent 属性上放置了一个JsonIgnore 属性。

这显然意味着父节点没有被序列化为结果 JSON 输出中每个节点的一部分。

当我反序列化相同的 JSON 字符串时,我希望为 Node 对象分配正确的 Parent,以便我可以轻松地向上遍历树。实现这一目标的最干净、最简单的方法是什么?

[JsonObject]
public class Node : IEnumerable<Node>
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    [JsonIgnore]
    public Node Parent { get; private set; }

    [JsonProperty("Children")]
    private readonly Dictionary<Guid, Node> _children = new Dictionary<Guid, Node>();

    public Node()
    {
        Id = Guid.NewGuid();
    }

    public void Add(Node departmentNode)
    {
        if (node.Parent != null)
        {
            node.Parent._children.Remove(node.Id);
        }

        node.Parent = this;
        _children.Add(node.Id, node);
    }

    public IEnumerator<Node> GetEnumerator()
    {
        return _children.Values.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

【问题讨论】:

    标签: c# json serialization json.net deserialization


    【解决方案1】:

    您可以完全摆脱 Parent 并在需要找到它时使用 FindParent(node.Id) 之类的东西。

    如果这不可行(应该可行)并且您需要有父引用,我的建议是遍历树并在反序列化后设置父引用。

    【讨论】:

    • 是的,可以。 FindParent(node.Id) 方法的缺点是我总是需要使用根部门作为起点。有时我可能只想将一个子部门作为参数传递给一个方法,并且能够轻松地向上走树。我目前有你的建议的工作版本,并将对其进行测试。谢谢!
    【解决方案2】:

    我为解决这个问题所做的是忽略 Parent 的序列化并实现一个名为 Children 的公共属性,该属性设置我的私有 ChildrenDict收藏。当我将孩子添加到私有字典时,我还设置了每个孩子的 Parent 属性。

    就我个人而言,我不喜欢用 JSON 特定的属性来污染我的数据类,因为我喜欢有一个独立于序列化器的干净设计。

    这么说,最终解决方案不使用JsonIgnoreAttribute标签并定义:

    • 一个私有的无参数构造函数,由 JSON 反序列化器使用
    • 私有 Parent 属性(被 JSON 序列化程序忽略)
    • 公共 GetParent() 方法(供您自己使用)
    • parent 作为参数的公共构造函数(供您自己使用)

    也可以定义一个 SetParent() 方法,尽管在我的代码中我根本不需要它。

    此代码已使用 NewtonsoftJson 序列化和 DotNET 4.5.2 进行了测试

    using System.Collections.Generic;
    using System.Linq;
    
    namespace JsonSerializableNode
    {
        public class Node
        {
            private Node() { } // used for deserializing
    
            public Node(string name, Node parent) // used everywhere else in your code
            {
                Name = name;
                Parent = parent;
            }
    
            public string Name { get; set; }
    
            private Node Parent { get; set; }
    
            public Node GetParent()
            {
                return Parent;
            }
    
            public Node[] Children
            {
                get
                {
                    return ChildrenDict.Values.ToArray();
                }
    
                set
                {
                    ChildrenDict.Clear();
                    if (value == null || value.Count <= 0) return;
                    foreach (Node child in value)
                        Add(child);
                }
            }
    
            // One could use a typed OrderedDictionary here, since Json lists guarantee the order of the children:
            private Dictionary<string, Node> ChildrenDict { get; } = new Dictionary<string, Node>();
    
            public Node Add(Node child)
            {
                ChildrenDict.Add(child.Name, child);
                child.Parent = this;
                return child;
            }
    
            public Node Get(string name)
            {
                return ChildrenDict[name];
            }
    
            public bool Remove(string name)
            {
                return ChildrenDict.Remove(name);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多