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

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

这显然意味着父级未被序列化为生成的JSON输出中的每个节点的一部分。

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

 [JsonObject] public class Node : IEnumerable { public Guid Id { get; set; } public string Name { get; set; } [JsonIgnore] public Node Parent { get; private set; } [JsonProperty("Children")] private readonly Dictionary _children = new Dictionary(); 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 GetEnumerator() { return _children.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } 

您可以完全摆脱Parent,并在需要查找时使用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 ChildrenDict { get; } = new Dictionary(); 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); } } }