JSON 的通用树
Generic Tree to JSON
我有一个代表组织结构图中员工的通用树结构。
树由自定义 Node<Person>
对象的图表组成,这些对象相互引用,其他属性(如级别)显示它们在树、父级、兄弟姐妹等中的级别。
我必须序列化这个组织结构图的一部分,从一个特定的人向下到他们下面的每个人,我在名为 SelfAndDescendants()
的节点对象上有一个方法,return 是一个 IEnumerable<Node<Person>>
。
所以基本上我在树中找到特定人的 Node
,然后将他们和他们的所有后代放在 IEnumerable
中。这部分工作正常。
这就是我被困的地方。我现在需要将 IEnumerable
组 Nodes
放入分层 JSON.
我的第一次尝试只是将它直接扔给 JSON 序列化程序,但这不起作用(我也没有真正期望它起作用),因为它是一组通用 Node
对象。在 Node
对象上有一个 Value
属性 将 return 一个 Person
对象......这是我需要进入 JSON(只是名字)。
string json = JsonConvert.SerializeObject(personNode.SelfAndDescendants.ToList());
这显然是在尝试序列化一个 List<Node<Person>>
,这不是我需要的。 JSON return 所需要的只是一个具有简单 Person
对象 Name
的分层格式。没有别的。
我是否必须在循环中手动执行任何操作才能构建自定义 JSON 和 return?
这不是 this post 的副本,因为我在这里处理的是通用递归树,而不是简单的通用数据结构。
我是否必须实施自定义 JsonConverter
?这如何处理树中的一系列 Node
个对象?
节点 class 具有各种属性,但它基本上看起来像这样:
public class Node<T> : IEqualityComparer, IEnumerable<T>, IEnumerable<Node<T>> {
public Node(T value) {
Value = value;
}
public Node<T> this[int index] {
get {
return _children[index];
}
}
public Node<T> Add(T value, int index = -1) {
var childNode = new Node<T>(value);
Add(childNode, index);
return childNode;
}
public IEnumerable<Node<T>> SelfAndDescendants {
get {
return this.ToIEnumarable().Concat(Children.SelectMany(c => c.SelfAndDescendants));
}
}
}
Person class 只是代表一个人的 POCO class。此 class 已经为系统的另一部分正确地序列化为 JSON。
[JsonObject]
public class Person {
public string Title { get; set; }
public DateTime DateOfBirth { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public Gender Gender { get; set; }
public List<StreetAddress> Addresses { get; set; }
... etc
}
期望的输出是组织结构图,显示 JSON 中人员的级别。所以他们老板手下的员工,他们老板手下的那个老板,等等
JSON在这方面非常简单,就是人名和头衔。它甚至可以是每个员工一个字符串。
您想通过在 class 和所需成员上添加序列化属性,然后序列化为字符串
来描述如何序列化此 class
string nodes = JsonConvert.SerializeObject<Node<Person>>(personNode);
[JsonObject]
public class Node<T> : IEqualityComparer, IEnumerable<T>, IEnumerable<Node<T>> {
[JsonProperty]
public IEnumerable<Node<T>> Children { get { return _children; } }
...
}
是的,考虑到您的限制,我认为创建自定义 JsonConverter
是针对这种情况的合适解决方案。它实际上写起来非常简单,只要 Node<T>
具有 public 属性以允许至少对 Value
和 Children
进行读取访问。您不必担心循环;当序列化程序通过 JArray.FromObject
调用遍历 Children
集合时,它会为每个子项回调转换器。
我会这样写:
public class OrgChartConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Node<Person>));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Node<Person> node = (Node<Person>)value;
JObject obj = new JObject();
obj.Add("Name", node.Value.Name);
obj.Add("Subordinates", JArray.FromObject(node.Children, serializer));
obj.WriteTo(writer);
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
然后,像这样使用转换器:
var settings = new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new OrgChartConverter() },
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(rootNode, settings);
我有一个代表组织结构图中员工的通用树结构。
树由自定义 Node<Person>
对象的图表组成,这些对象相互引用,其他属性(如级别)显示它们在树、父级、兄弟姐妹等中的级别。
我必须序列化这个组织结构图的一部分,从一个特定的人向下到他们下面的每个人,我在名为 SelfAndDescendants()
的节点对象上有一个方法,return 是一个 IEnumerable<Node<Person>>
。
所以基本上我在树中找到特定人的 Node
,然后将他们和他们的所有后代放在 IEnumerable
中。这部分工作正常。
这就是我被困的地方。我现在需要将 IEnumerable
组 Nodes
放入分层 JSON.
我的第一次尝试只是将它直接扔给 JSON 序列化程序,但这不起作用(我也没有真正期望它起作用),因为它是一组通用 Node
对象。在 Node
对象上有一个 Value
属性 将 return 一个 Person
对象......这是我需要进入 JSON(只是名字)。
string json = JsonConvert.SerializeObject(personNode.SelfAndDescendants.ToList());
这显然是在尝试序列化一个 List<Node<Person>>
,这不是我需要的。 JSON return 所需要的只是一个具有简单 Person
对象 Name
的分层格式。没有别的。
我是否必须在循环中手动执行任何操作才能构建自定义 JSON 和 return?
这不是 this post 的副本,因为我在这里处理的是通用递归树,而不是简单的通用数据结构。
我是否必须实施自定义 JsonConverter
?这如何处理树中的一系列 Node
个对象?
节点 class 具有各种属性,但它基本上看起来像这样:
public class Node<T> : IEqualityComparer, IEnumerable<T>, IEnumerable<Node<T>> {
public Node(T value) {
Value = value;
}
public Node<T> this[int index] {
get {
return _children[index];
}
}
public Node<T> Add(T value, int index = -1) {
var childNode = new Node<T>(value);
Add(childNode, index);
return childNode;
}
public IEnumerable<Node<T>> SelfAndDescendants {
get {
return this.ToIEnumarable().Concat(Children.SelectMany(c => c.SelfAndDescendants));
}
}
}
Person class 只是代表一个人的 POCO class。此 class 已经为系统的另一部分正确地序列化为 JSON。
[JsonObject]
public class Person {
public string Title { get; set; }
public DateTime DateOfBirth { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public Gender Gender { get; set; }
public List<StreetAddress> Addresses { get; set; }
... etc
}
期望的输出是组织结构图,显示 JSON 中人员的级别。所以他们老板手下的员工,他们老板手下的那个老板,等等
JSON在这方面非常简单,就是人名和头衔。它甚至可以是每个员工一个字符串。
您想通过在 class 和所需成员上添加序列化属性,然后序列化为字符串
来描述如何序列化此 classstring nodes = JsonConvert.SerializeObject<Node<Person>>(personNode);
[JsonObject]
public class Node<T> : IEqualityComparer, IEnumerable<T>, IEnumerable<Node<T>> {
[JsonProperty]
public IEnumerable<Node<T>> Children { get { return _children; } }
...
}
是的,考虑到您的限制,我认为创建自定义 JsonConverter
是针对这种情况的合适解决方案。它实际上写起来非常简单,只要 Node<T>
具有 public 属性以允许至少对 Value
和 Children
进行读取访问。您不必担心循环;当序列化程序通过 JArray.FromObject
调用遍历 Children
集合时,它会为每个子项回调转换器。
我会这样写:
public class OrgChartConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Node<Person>));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Node<Person> node = (Node<Person>)value;
JObject obj = new JObject();
obj.Add("Name", node.Value.Name);
obj.Add("Subordinates", JArray.FromObject(node.Children, serializer));
obj.WriteTo(writer);
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
然后,像这样使用转换器:
var settings = new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new OrgChartConverter() },
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(rootNode, settings);