反序列化json树结构并设置父项

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反序列化json树结构并设置父项相关的知识,希望对你有一定的参考价值。

这似乎是一个非常基本的问题,但我很想找到一个优雅的解决方案。我有一个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();
    }
}
答案

当你需要找到它时,你可以完全摆脱父母并使用像FindParent(node.Id)这样的东西。

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

另一答案

我所做的就是忽略Parent的序列化并实现一个名为Children的公共属性,它设置我的私有ChildrenDict集合。当我将子项添加到私有字典时,我还设置了每个子项的Parent属性。

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

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

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

也可以定义一个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);
        }
    }
}

以上是关于反序列化json树结构并设置父项的主要内容,如果未能解决你的问题,请参考以下文章

LintCode 7.Serialize and Deserialize Binary Tree(含测试代码)

反序列化嵌套 JSON 结构时,Serde 返回 SyntaxError “预期值”

Lintcode---二叉树的序列化和反序列化

如何检查 JSON 中的值类型并决定是不是反序列化?

当链接器设置为全部链接时,JSON 反序列化失败

在 C# 中从 JSON 反序列化数组