(精華)2020年6月26日 C#類庫 樹結構幫助類

愚公搬程式碼發表於2020-06-26
using System;
using System.Collections.Generic;
using System.Linq;

namespace Core.Util
{
    /// <summary>
    /// 樹結構幫助類
    /// </summary>
    public class TreeHelper
    {
        #region 外部介面

        /// <summary>
        /// 建造樹結構
        /// </summary>
        /// <param name="allNodes">所有的節點</param>
        /// <returns></returns>
        public static List<T> BuildTree<T>(List<T> allNodes) where T : TreeModel, new()
        {
            List<T> resData = new List<T>();
            var rootNodes = allNodes.Where(x => x.ParentId == "0" || x.ParentId.IsNullOrEmpty()).ToList();
            resData = rootNodes;
            resData.ForEach(aRootNode =>
            {
                if (HaveChildren(allNodes, aRootNode.Id))
                    aRootNode.Children = _GetChildren(allNodes, aRootNode);
            });

            return resData;
        }

        /// <summary>
        /// 獲取所有子節點
        /// 注:包括自己
        /// </summary>
        /// <typeparam name="T">節點型別</typeparam>
        /// <param name="allNodes">所有節點</param>
        /// <param name="parentNode">父節點</param>
        /// <param name="includeSelf">是否包括自己</param>
        /// <returns></returns>
        public static List<T> GetChildren<T>(List<T> allNodes, T parentNode, bool includeSelf) where T : TreeModel
        {
            List<T> resList = new List<T>();
            if (includeSelf)
                resList.Add(parentNode);
            _getChildren(allNodes, parentNode, resList);

            return resList;

            void _getChildren(List<T> _allNodes, T _parentNode, List<T> _resNodes)
            {
                var children = _allNodes.Where(x => x.ParentId == _parentNode.Id).ToList();
                _resNodes.AddRange(children);
                children.ForEach(aChild =>
                {
                    _getChildren(_allNodes, aChild, _resNodes);
                });
            }
        }

        #endregion

        #region 私有成員

        /// <summary>
        /// 獲取所有子節點
        /// </summary>
        /// <typeparam name="T">樹模型(TreeModel或繼承它的模型)</typeparam>
        /// <param name="nodes">所有節點列表</param>
        /// <param name="parentNode">父節點Id</param>
        /// <returns></returns>
        private static List<object> _GetChildren<T>(List<T> nodes, T parentNode) where T : TreeModel, new()
        {
            Type type = typeof(T);
            var properties = type.GetProperties().ToList();
            List<object> resData = new List<object>();
            var children = nodes.Where(x => x.ParentId == parentNode.Id).ToList();
            children.ForEach(aChildren =>
            {
                T newNode = new T();
                resData.Add(newNode);

                //賦值屬性
                properties.Where(x => x.CanWrite).ForEach(aProperty =>
                {
                    var value = aProperty.GetValue(aChildren, null);
                    aProperty.SetValue(newNode, value);
                });
                //設定深度
                newNode.Level = parentNode.Level + 1;

                if (HaveChildren(nodes, aChildren.Id))
                    newNode.Children = _GetChildren(nodes, newNode);
            });

            return resData;
        }

        /// <summary>
        /// 判斷當前節點是否有子節點
        /// </summary>
        /// <typeparam name="T">樹模型</typeparam>
        /// <param name="nodes">所有節點</param>
        /// <param name="nodeId">當前節點Id</param>
        /// <returns></returns>
        private static bool HaveChildren<T>(List<T> nodes, string nodeId) where T : TreeModel, new()
        {
            return nodes.Exists(x => x.ParentId == nodeId);
        }

        #endregion
    }
}

相關文章