使用 C# 动态构建 JSON 树,以供 JavaScript 组件使用





5.00/5 (5投票s)
使用 C# 动态构建 JSON 树,以供 JavaScript 组件使用
使用 C# 动态构建 JSON 树,用于 Javascript 组件
引言
现在,许多 JavaScript 组件在使用数据时都会使用 JSON,原因很明显。但是,某些构建树形结构的组件,比如 这个,需要 JSON 树。构建静态 JSON 树很容易,但是如何构建动态 JSON 树并将其传递给像上面提到的那些组件呢? 这就是本文的全部内容。
第一步:构建树的类型表示
我们需要采取的第一步是在 C# 中构建一棵树,然后将该树转换为 JSON 树。 但是,我们可能在数据库中的某个地方有一个树结构。 我看到的大多数时候在数据库中表示树的结构是具有 Id
和 ParentId
的记录,因此我将使用它作为数据库中树的表示形式。但是,由于我们没有任何数据库,内存中的集合可以满足我们的需求,我们的集合看起来像这样
public class Cate
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Name { get; set; }
}
var cats = new List<Cate>
{
new Cate {Id = 1, ParentId = null, Name = "First"},
new Cate {Id = 2, ParentId = null, Name = "Second"},
new Cate {Id = 3, ParentId = null, Name = "Thrid"},
new Cate {Id = 4, ParentId = null, Name = "Fourth"},
new Cate {Id = 5, ParentId = 4, Name = "SubFourth1"},
new Cate {Id = 6, ParentId = 4, Name = "SubFourth2"},
new Cate {Id = 7, ParentId = 5, Name = "Sub_SubFourth1"},
new Cate {Id = 8, ParentId = null, Name = "Sixth"},
new Cate {Id = 9, ParentId = null, Name = "Seventh"},
new Cate {Id = 10, ParentId = 9, Name = "SubSeventh1"},
new Cate {Id = 11, ParentId = 9, Name = "SubSeventh2"},
new Cate {Id = 12, ParentId = null, Name = "Eighth"},
new Cate {Id = 13, ParentId = null, Name = "Ninth"},
new Cate {Id = 14, ParentId = null, Name = "Tenth"},
new Cate {Id = 15, ParentId = null, Name = "Eleventh"},
new Cate {Id = 16, ParentId = 15, Name = "SubEleventh"},
new Cate {Id = 17, ParentId = 16, Name = "Sub_SubEleventh"},
};
现在我们有了构建树所需的数据。接下来我们需要一个类型来表示我们的树,每棵树都由许多节点组成,因此我们需要在此处描述我们的节点,我们的类型如下所示
class Node
{
[JsonProperty(PropertyName = "nodes")]
public List<Node> Children = new List<Node>();
public bool ShouldSerializeChildren()
{
return (Children.Count > 0);
}
//[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Node Parent { get; set; }
public int Id { get; set; }
public int? ParentId { get; set; }
[JsonProperty(PropertyName = "text")]
public string Name { get; set; }
}
为了更好地理解我们的 Node
类,让我们看一下这张树的图片
每个 Node
都有一个父节点,因此我们声明一个名为 Parent
的 Node
类型的属性。在每个 Node
中,我们有一些数据,在本例中为 Id
、ParentId
和 Name
,并且 Node
可以有许多子节点,因此我们声明一个名为 Children
的属性,该属性保存节点列表作为其子节点,并且由于我们使用 Json.NET 从 C# 树结构转换为 JSON,因此 ShouldSerializeChildren
负责称为“条件属性序列化”的内容。我们需要这个,因为如果我们有一个没有子节点的节点,Json.NET 的默认行为是将其作为空的节点集合包含在我们的树中,例如:"nodes": []
,最后我们有几个属性,除了在序列化中更改我们属性的名称之外,这里不做任何事情。
第二步:用数据填充树
现在我们有了构建简单树所需的所有类型,现在我们需要做的是用数据填充我们的树结构,我在这里找到了一种方法,并对其进行了稍微更改以适应我的需求
public IEnumerable<Node> RawCollectionToTree(List<Cate> collection)
{
var treeDictionary = new Dictionary<int?, Node>();
collection.ForEach(x => treeDictionary.Add(x.Id,
new Node { Id = x.Id, ParentId = x.ParentId, Name = x.Name }));
foreach (var item in treeDictionary.Values)
{
if (item.ParentId != null)
{
Node proposedParent;
if (treeDictionary.TryGetValue(item.ParentId, out proposedParent))
{
item.Parent = proposedParent;
proposedParent.Children.Add(item);
}
}
}
return treeDictionary.Values.Where(x => x.Parent == null);
}
在这里,我们构建了一个名为 treeDictionary
的字典,并使用我们的数据填充了该字典。此字典的键将是我们的 Cate
类型的 Id,而值将是节点的数据。在我们填充了我们的 dictionary
之后,是时候将节点的 Parent
和 Children
属性分配给 dictionary
中对应的 Parent
和 Children
。在这里,我们 foreach
遍历我们的字典,如果我们的节点有一个 ParentId
,我们将继续获取该 Parent
,并将其分配给当前节点 (item) 的 Parent
属性,并添加到 Parent (proposedParent)
其 Children
,这里是我们的 Item,并返回 Parent
为 null
的 dictionary
,现在我们在 C# 中有一棵树
现在我们需要将这棵树转换为 JSON。
第三步:将 C# 树转换为 JSON 树
最后一步也是最简单的一步,是将我们的 C# 树转换为 JSON,但是您可能会遇到一些问题,我将在下面解释。对于转换,我们使用此代码
var tree= roots.RawCollectionToTree(cats).ToList();
string json = JsonConvert.SerializeObject(tree, Formatting.Indented,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
});
在这里,我们首先使用我们的 RawCollectionToTree
方法从我们的集合中构建一棵树,然后我们将其转换为 JSON。还有两件事可能值得指出,在这里我们使用带有两个属性的 JsonSerializerSettings
,第一个 ReferenceLoopHandling
负责忽略自引用循环,这可能会导致堆栈溢出异常,第二个属性是 null
值序列化,我们告诉序列化程序忽略 null
值。现在我们有一个 JSON 树,它类似于这样
[
{
"Id": 1,
"text": "First"
},
{
"Id": 2,
"text": "Second"
},
{
"Id": 3,
"text": "Thrid"
},
{
"nodes": [
{
"nodes": [
{
"Id": 7,
"ParentId": 5,
"text": "Sub_SubFourth1"
}
],
"Id": 5,
"ParentId": 4,
"text": "SubFourth1"
},
{
"Id": 6,
"ParentId": 4,
"text": "SubFourth2"
}
],
"Id": 4,
"text": "Fourth"
},
{
"Id": 8,
"text": "Sixth"
},
{
"nodes": [
{
"Id": 10,
"ParentId": 9,
"text": "SubSeventh1"
},
{
"Id": 11,
"ParentId": 9,
"text": "SubSeventh2"
}
],
"Id": 9,
"text": "Seventh"
},
{
"Id": 12,
"text": "Eighth"
},
{
"Id": 13,
"text": "Ninth"
},
{
"Id": 14,
"text": "Tenth"
},
{
"nodes": [
{
"nodes": [
{
"Id": 17,
"ParentId": 16,
"text": "Sub_SubEleventh"
}
],
"Id": 16,
"ParentId": 15,
"text": "SubEleventh"
}
],
"Id": 15,
"text": "Eleventh"
}
]
您可以从这里下载示例项目。