65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2016年5月30日

CPOL

3分钟阅读

viewsIcon

31860

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

使用 C# 动态构建 JSON 树,用于 Javascript 组件

引言

现在,许多 JavaScript 组件在使用数据时都会使用 JSON,原因很明显。但是,某些构建树形结构的组件,比如 这个,需要 JSON 树。构建静态 JSON 树很容易,但是如何构建动态 JSON 树并将其传递给像上面提到的那些组件呢? 这就是本文的全部内容。

第一步:构建树的类型表示

我们需要采取的第一步是在 C# 中构建一棵树,然后将该树转换为 JSON 树。 但是,我们可能在数据库中的某个地方有一个树结构。 我看到的大多数时候在数据库中表示树的结构是具有 IdParentId 的记录,因此我将使用它作为数据库中树的表示形式。但是,由于我们没有任何数据库,内存中的集合可以满足我们的需求,我们的集合看起来像这样

   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 都有一个父节点,因此我们声明一个名为 ParentNode 类型的属性。在每个 Node 中,我们有一些数据,在本例中为 IdParentIdName,并且 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 之后,是时候将节点的 ParentChildren 属性分配给 dictionary 中对应的 ParentChildren。在这里,我们 foreach 遍历我们的字典,如果我们的节点有一个 ParentId,我们将继续获取该 Parent,并将其分配给当前节点 (item) 的 Parent 属性,并添加到 Parent (proposedParent)Children,这里是我们的 Item,并返回 Parentnulldictionary,现在我们在 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"
  }
]

您可以从这里下载示例项目。

© . All rights reserved.