反序列化 JSON 树结构并设置父级
本文关键字:设置 结构 JSON 反序列化 | 更新日期: 2023-09-27 18:34:50
这似乎是一个非常基本的问题,但我正在努力寻找一个优雅的解决方案。我有一个 Node 类,用于构建树结构。然后使用 JsonConvert.SerializeObject(..)
将其序列化为 JSON。为了防止序列化时循环引用,我在 Parent 属性上放置了一个 JsonIgnore
属性。
这显然意味着父节点不会作为生成的 JSON 输出中每个节点的一部分进行序列化。
当我反序列化相同的 JSON 字符串时,我希望 Node 对象分配了正确的父对象,以便我可以轻松地向上遍历树。实现这一目标的最干净、最简单的方法是什么?
[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)
的东西。
如果这不可行(应该是(,并且您需要有一个父引用,我的建议是遍历树并在反序列化后设置父引用。
我为解决这个问题所做的是忽略父级的序列化并实现一个名为 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);
}
}
}