Browse Source

Tree结构非递归实现

懒得勤快 1 year ago
parent
commit
b85fd17b53

+ 1 - 1
Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj

@@ -3,7 +3,7 @@
         <TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5;net6;net7;net8</TargetFrameworks>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>2024.3.2</Version>
+        <Version>2024.3.3</Version>
         <Authors>懒得勤快</Authors>
         <Description>全龄段友好的C#万能工具库,码数吐司库,不管你是菜鸟新手还是骨灰级玩家都能轻松上手,Masuit.Tools基础公共库(适用于.NET4.6.1/.NET Standard2.0及以上项目),包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。
             官网教程:https://masuit.tools

+ 945 - 600
Masuit.Tools.Abstractions/Models/TreeExtensions.cs

@@ -4,757 +4,1102 @@ using System.Linq;
 using System.Linq.Expressions;
 using Masuit.Tools.Systems;
 
-namespace Masuit.Tools.Models
+namespace Masuit.Tools.Models;
+
+/// <summary>
+/// 树形数据扩展
+/// </summary>
+public static class TreeExtensions
 {
     /// <summary>
-    /// 树形数据扩展
+    /// 过滤
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="items"></param>
+    /// <param name="func"></param>
+    /// <returns></returns>
+    public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Func<T, bool> func) where T : class, ITreeChildren<T>
+    {
+        return Flatten(items).Where(func);
+    }
+
+    /// <summary>
+    /// 过滤
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="items"></param>
+    /// <param name="func"></param>
+    /// <returns></returns>
+    public static IEnumerable<Tree<T>> Filter<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, bool> func) where T : class
+    {
+        return Flatten(items).Where(func);
+    }
+
+    /// <summary>
+    /// 过滤
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="item"></param>
+    /// <param name="func"></param>
+    /// <returns></returns>
+    public static IEnumerable<T> Filter<T>(this T item, Func<T, bool> func) where T : class, ITreeChildren<T>
+    {
+        return Flatten(item).Where(func);
+    }
+
+    /// <summary>
+    /// 过滤
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="item"></param>
+    /// <param name="func"></param>
+    /// <returns></returns>
+    public static IEnumerable<Tree<T>> Filter<T>(this Tree<T> item, Func<Tree<T>, bool> func) where T : class
+    {
+        return Flatten(item).Where(func);
+    }
+
+    /// <summary>
+    /// 平铺开
     /// </summary>
-    public static class TreeExtensions
+    /// <typeparam name="T"></typeparam>
+    /// <param name="items"></param>
+    /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
+    /// <returns></returns>
+    public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
     {
-        /// <summary>
-        /// 过滤
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="items"></param>
-        /// <param name="func"></param>
-        /// <returns></returns>
-        public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Func<T, bool> func) where T : class, ITreeChildren<T>
+        if (items == null)
+        {
+            yield break;
+        }
+
+        // 使用一个栈来存储待处理的节点
+        var stack = new Stack<T>();
+        // 首先将所有项压入栈中
+        foreach (var item in items)
         {
-            foreach (var item in items.Where(i => i != null))
+            stack.Push(item);
+        }
+
+        // 循环直到栈为空
+        while (stack.Count > 0)
+        {
+            // 弹出栈顶的节点
+            var currentItem = stack.Pop();
+            yield return currentItem;
+
+            // 为当前节点设置子节点,如果optionAction不为空,则对每个子节点执行操作
+            var children = currentItem.Children ?? new List<T>();
+            foreach (var child in children)
             {
-                item.Children ??= new List<T>();
-                item.Children = item.Children.Filter(func).ToList();
-                if (item.Children.Any() || func(item))
-                {
-                    yield return item;
-                }
+                optionAction?.Invoke(child, currentItem);
+                stack.Push(child); // 将子节点压入栈中
             }
         }
+    }
 
-        /// <summary>
-        /// 过滤
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="items"></param>
-        /// <param name="func"></param>
-        /// <returns></returns>
-        public static IEnumerable<Tree<T>> Filter<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, bool> func) where T : class
+    /// <summary>
+    /// 平铺开
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="p"></param>
+    /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
+    /// <returns></returns>
+    public static IEnumerable<T> Flatten<T>(this T p, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
+    {
+        if (p == null)
         {
-            foreach (var item in items.Where(i => i != null))
+            yield break;
+        }
+
+        // 使用一个队列来存储待处理的节点
+        var queue = new Queue<T>();
+        queue.Enqueue(p);
+
+        while (queue.Count > 0)
+        {
+            // 从队列中出队一个节点
+            var currentItem = queue.Dequeue();
+
+            // 将当前节点返回
+            yield return currentItem;
+
+            // 获取当前节点的子节点,如果子节点列表不存在,则初始化为空列表
+            var children = currentItem.Children ?? new List<T>();
+
+            // 将所有子节点入队
+            foreach (var child in children)
             {
-                item.Children ??= new List<Tree<T>>();
-                item.Children = item.Children.Filter(func).ToList();
-                if (item.Children.Any() || func(item))
-                {
-                    yield return item;
-                }
+                // 执行平铺时的操作(如果有的话)
+                optionAction?.Invoke(child, currentItem);
+                queue.Enqueue(child);
             }
         }
+    }
 
-        /// <summary>
-        /// 过滤
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="item"></param>
-        /// <param name="func"></param>
-        /// <returns></returns>
-        public static IEnumerable<T> Filter<T>(this T item, Func<T, bool> func) where T : class, ITreeChildren<T>
+    /// <summary>
+    /// 平铺开任意树形结构数据
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="items"></param>
+    /// <param name="selector"></param>
+    /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
+    /// <returns></returns>
+    public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector, Action<T, T> optionAction = null)
+    {
+        if (items == null)
         {
-            return new[] { item }.Filter(func);
+            yield break;
         }
 
-        /// <summary>
-        /// 过滤
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="item"></param>
-        /// <param name="func"></param>
-        /// <returns></returns>
-        public static IEnumerable<Tree<T>> Filter<T>(this Tree<T> item, Func<Tree<T>, bool> func) where T : class
+        // 使用一个队列来存储待处理的节点
+        var queue = new Queue<T>();
+        // 首先将所有项加入队列
+        foreach (var item in items)
         {
-            return new[] { item }.Filter(func);
+            queue.Enqueue(item);
         }
 
-        /// <summary>
-        /// 平铺开
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="items"></param>
-        /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
-        /// <returns></returns>
-        public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
+        // 循环直到队列为空
+        while (queue.Count > 0)
         {
-            foreach (var item in items)
+            // 从队列中取出当前节点
+            var currentItem = queue.Dequeue();
+
+            // 将当前节点返回
+            yield return currentItem;
+
+            // 获取当前节点的所有子节点
+            var children = selector(currentItem) ?? new List<T>();
+
+            // 将所有子节点加入队列
+            foreach (var child in children)
             {
-                yield return item;
-                item.Children ??= new List<T>();
-                item.Children.ForEach(c => optionAction?.Invoke(c, item));
-                foreach (var children in item.Children.Flatten(optionAction))
-                {
-                    yield return children;
-                }
+                // 执行平铺时的操作(如果有的话)
+                optionAction?.Invoke(child, currentItem);
+                queue.Enqueue(child);
             }
         }
+    }
 
-        /// <summary>
-        /// 平铺开
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="p"></param>
-        /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
-        /// <returns></returns>
-        public static IEnumerable<T> Flatten<T>(this T p, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
+    /// <summary>
+    /// 平铺开
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="items"></param>
+    /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
+    /// <returns></returns>
+    public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
+    {
+        if (items == null)
         {
-            yield return p;
-            foreach (var item in p.Children)
-            {
-                yield return item;
-                item.Children ??= new List<T>();
-                item.Children.ForEach(c => optionAction?.Invoke(c, item));
-                foreach (var children in item.Children.Flatten())
-                {
-                    yield return children;
-                }
-            }
+            yield break;
         }
 
-        /// <summary>
-        /// 平铺开任意树形结构数据
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="items"></param>
-        /// <param name="selector"></param>
-        /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
-        /// <returns></returns>
-        public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector, Action<T, T> optionAction = null)
+        // 使用一个队列来存储待处理的节点
+        var queue = new Queue<Tree<T>>();
+        // 首先将所有项加入队列
+        foreach (var item in items)
         {
-            foreach (var item in items)
-            {
-                yield return item;
-                selector(item).ForEach(c => optionAction?.Invoke(c, item));
-                foreach (var children in selector(item).Flatten(selector))
-                {
-                    yield return children;
-                }
-            }
+            queue.Enqueue(item);
         }
 
-        /// <summary>
-        /// 平铺开
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="items"></param>
-        /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
-        /// <returns></returns>
-        public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
+        // 循环直到队列为空
+        while (queue.Count > 0)
         {
-            foreach (var item in items)
+            // 从队列中取出当前节点
+            var currentItem = queue.Dequeue();
+
+            // 将当前节点返回
+            yield return currentItem;
+
+            // 获取当前节点的所有子节点,如果子节点列表不存在,则初始化为空列表
+            var children = currentItem.Children ?? new List<Tree<T>>();
+
+            // 将所有子节点加入队列
+            foreach (var child in children)
             {
-                yield return item;
-                item.Children ??= new List<Tree<T>>();
-                item.Children.ForEach(c => optionAction?.Invoke(c, item));
-                foreach (var tree in item.Children.Flatten())
-                {
-                    yield return tree;
-                }
+                // 执行平铺时的操作(如果有的话)
+                optionAction?.Invoke(child, currentItem);
+                queue.Enqueue(child);
             }
         }
+    }
+
+    /// <summary>
+    /// 平铺开
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="p"></param>
+    /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
+    /// <returns></returns>
+    public static IEnumerable<Tree<T>> Flatten<T>(this Tree<T> p, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
+    {
+        if (p == null)
+        {
+            yield break;
+        }
 
-        /// <summary>
-        /// 平铺开
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="p"></param>
-        /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
-        /// <returns></returns>
-        public static IEnumerable<Tree<T>> Flatten<T>(this Tree<T> p, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
+        // 使用一个队列来存储待处理的节点
+        var queue = new Queue<Tree<T>>();
+        queue.Enqueue(p);
+
+        // 遍历队列直到它为空
+        while (queue.Count > 0)
         {
-            yield return p;
-            foreach (var item in p.Children)
+            // 从队列中取出当前节点
+            var currentItem = queue.Dequeue();
+
+            // 将当前节点返回
+            yield return currentItem;
+
+            // 获取当前节点的子节点列表,如果为空则初始化为空列表
+            var children = currentItem.Children ?? new List<Tree<T>>();
+
+            // 将所有子节点添加到队列中
+            foreach (var child in children)
             {
-                yield return item;
-                item.Children ??= new List<Tree<T>>();
-                item.Children.ForEach(c => optionAction?.Invoke(c, item));
-                foreach (var tree in item.Children.Flatten())
-                {
-                    yield return tree;
-                }
+                // 执行平铺时的操作(如果有的话)
+                optionAction?.Invoke(child, currentItem);
+                queue.Enqueue(child);
             }
         }
+    }
 
-        /// <summary>
-        /// 平铺开任意树形结构数据
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="items"></param>
-        /// <param name="selector"></param>
-        /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
-        /// <returns></returns>
-        public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, IEnumerable<Tree<T>>> selector, Action<Tree<T>, Tree<T>> optionAction = null)
+    /// <summary>
+    /// 平铺开任意树形结构数据
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="items"></param>
+    /// <param name="selector"></param>
+    /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
+    /// <returns></returns>
+    public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, IEnumerable<Tree<T>>> selector, Action<Tree<T>, Tree<T>> optionAction = null)
+    {
+        if (items == null)
         {
-            foreach (var item in items)
-            {
-                yield return item;
-                item.Children.ForEach(c => optionAction?.Invoke(c, item));
-                foreach (var tree in selector(item).Flatten(selector))
-                {
-                    yield return tree;
-                }
-            }
+            yield break;
         }
 
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, string>> idSelector, Expression<Func<T, string>> pidSelector, string topValue = default) where T : ITreeParent<T>, ITreeChildren<T>
-        {
-            return ToTree<T, string>(source, idSelector, pidSelector, topValue);
-        }
-
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, int>> idSelector, Expression<Func<T, int>> pidSelector, int topValue = 0) where T : ITreeParent<T>, ITreeChildren<T>
-        {
-            return ToTree<T, int>(source, idSelector, pidSelector, topValue);
-        }
-
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, long>> idSelector, Expression<Func<T, long>> pidSelector, long topValue = 0) where T : ITreeParent<T>, ITreeChildren<T>
-        {
-            return ToTree<T, long>(source, idSelector, pidSelector, topValue);
-        }
-
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, Guid>> idSelector, Expression<Func<T, Guid>> pidSelector, Guid topValue = default) where T : ITreeParent<T>, ITreeChildren<T>
-        {
-            return ToTree<T, Guid>(source, idSelector, pidSelector, topValue);
-        }
-
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <typeparam name="TKey"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey>> pidSelector, TKey topValue = default) where T : ITreeParent<T>, ITreeChildren<T> where TKey : IComparable
-        {
-            if (source is IQueryable<T> queryable)
-            {
-                source = queryable.ToList();
-            }
+        // 使用一个队列来存储待处理的节点
+        var queue = new Queue<Tree<T>>();
+        // 首先将所有项加入队列
+        foreach (var item in items)
+        {
+            queue.Enqueue(item);
+        }
+
+        // 循环直到队列为空
+        while (queue.Count > 0)
+        {
+            // 从队列中取出当前节点
+            var currentItem = queue.Dequeue();
 
-            if (idSelector.Body.ToString() == pidSelector.Body.ToString())
+            // 将当前节点返回
+            yield return currentItem;
+
+            // 获取当前节点的所有子节点
+            var children = selector(currentItem) ?? new List<Tree<T>>();
+
+            // 将所有子节点加入队列
+            foreach (var child in children)
             {
-                throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+                // 执行平铺时的操作(如果有的话)
+                optionAction?.Invoke(child, currentItem);
+                queue.Enqueue(child);
             }
+        }
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, string>> idSelector, Expression<Func<T, string>> pidSelector, string topValue = default) where T : ITreeParent<T>, ITreeChildren<T>
+    {
+        return ToTree<T, string>(source, idSelector, pidSelector, topValue);
+    }
 
-            var pidFunc = pidSelector.Compile();
-            var idFunc = idSelector.Compile();
-            return BuildTree(source.Where(t => t != null), idFunc, pidFunc, topValue).ToList();
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, int>> idSelector, Expression<Func<T, int>> pidSelector, int topValue = 0) where T : ITreeParent<T>, ITreeChildren<T>
+    {
+        return ToTree<T, int>(source, idSelector, pidSelector, topValue);
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, long>> idSelector, Expression<Func<T, long>> pidSelector, long topValue = 0) where T : ITreeParent<T>, ITreeChildren<T>
+    {
+        return ToTree<T, long>(source, idSelector, pidSelector, topValue);
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, Guid>> idSelector, Expression<Func<T, Guid>> pidSelector, Guid topValue = default) where T : ITreeParent<T>, ITreeChildren<T>
+    {
+        return ToTree<T, Guid>(source, idSelector, pidSelector, topValue);
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <typeparam name="TKey"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey>> pidSelector, TKey topValue = default) where T : ITreeParent<T>, ITreeChildren<T> where TKey : IComparable
+    {
+        if (source is IQueryable<T> queryable)
+        {
+            source = queryable.ToList();
         }
 
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source) where T : ITreeEntity<T, int>
+        if (idSelector.Body.ToString() == pidSelector.Body.ToString())
         {
-            return ToTree<T, int>(source);
+            throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
         }
 
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <typeparam name="TKey"></typeparam>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, TKey? topValue = default) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable
+        var pidFunc = pidSelector.Compile();
+        var idFunc = idSelector.Compile();
+        return BuildTree(source.Where(t => t != null), idFunc, pidFunc, topValue).ToList();
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T, int>
+    {
+        return ToTree<T, int>(source);
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <typeparam name="TKey"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="topValue"></param>
+    /// <returns></returns>
+    public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, TKey? topValue = null) where T : class, ITreeEntity<T, TKey> where TKey : struct, IComparable
+    {
+        if (source is IQueryable<T> queryable)
         {
-            if (source is IQueryable<T> queryable)
-            {
-                source = queryable.ToList();
-            }
+            source = queryable.ToList();
+        }
 
-            source = source.Where(t => t != null).ToList();
-            return BuildTree(source, topValue).ToList();
+        var list = source.Where(t => t != null).ToList();
+        return BuildTree(list, topValue).ToList();
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <typeparam name="TKey"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey?>> pidSelector, TKey? topValue = default) where T : ITreeChildren<T> where TKey : struct
+    {
+        if (source is IQueryable<T> queryable)
+        {
+            source = queryable.ToList();
         }
 
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <typeparam name="TKey"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey?>> pidSelector, TKey? topValue = default) where T : ITreeChildren<T> where TKey : struct
+        if (idSelector.Body.ToString() == pidSelector.Body.ToString())
         {
-            if (source is IQueryable<T> queryable)
-            {
-                source = queryable.ToList();
-            }
+            throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+        }
 
-            var pidFunc = pidSelector.Compile();
-            var idFunc = idSelector.Compile();
-            source = source.Where(t => t != null).ToList();
-            return BuildTree(source, idFunc, pidFunc, topValue).ToList();
+        var pidFunc = pidSelector.Compile();
+        var idFunc = idSelector.Compile();
+        source = source.Where(t => t != null).ToList();
+        return BuildTree(source, idFunc, pidFunc, topValue).ToList();
+    }
+
+    private static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, Func<T, TKey> idSelector, Func<T, TKey> pidSelector, TKey topValue = default) where T : ITreeChildren<T> where TKey : IComparable
+    {
+        // 创建一个字典,用于快速查找节点的子节点
+        var childrenLookup = new Dictionary<TKey, List<T>>();
+        var list = source as ICollection<T> ?? source.ToList();
+        foreach (var item in list.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
+        {
+            childrenLookup[idSelector(item)] = new List<T>();
         }
 
-        private static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, Func<T, TKey> idSelector, Func<T, TKey> pidSelector, TKey topValue = default) where T : ITreeChildren<T> where TKey : IComparable
+        // 构建树结构
+        foreach (var item in list.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item))))
         {
-            // 创建一个字典,用于快速查找节点的子节点
-            var childrenLookup = new Dictionary<TKey, List<T>>();
-            foreach (var item in source.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
-            {
-                childrenLookup[idSelector(item)] = new List<T>();
-            }
+            childrenLookup[pidSelector(item)].Add(item);
+        }
 
-            // 构建树结构
-            foreach (var item in source.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item))))
+        // 找到根节点,即没有父节点的节点
+        foreach (var root in list.Where(x => Equals(pidSelector(x), topValue)))
+        {
+            // 为根节点和所有子节点设置Children属性
+            // 使用队列来模拟递归过程
+            var queue = new Queue<T>();
+            queue.Enqueue(root);
+            while (queue.Count > 0)
             {
-                childrenLookup[pidSelector(item)].Add(item);
+                // 出队当前节点
+                var current = queue.Dequeue();
+
+                // 为当前节点设置子节点
+                if (childrenLookup.TryGetValue(idSelector(current), out var children))
+                {
+                    current.Children = children;
+                    foreach (var child in children)
+                    {
+                        // 如果子节点实现了ITreeParent接口,则设置其Parent属性
+                        if (child is ITreeParent<T> tree)
+                        {
+                            tree.Parent = current;
+                        }
+
+                        // 将子节点入队以继续处理
+                        queue.Enqueue(child);
+                    }
+                }
             }
 
-            // 找到根节点,即没有父节点的节点
-            foreach (var root in source.Where(x => Equals(pidSelector(x), topValue)))
+            yield return root;
+        }
+    }
+
+    internal static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, TKey? topValue = default) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable
+    {
+        // 创建一个字典,用于快速查找节点的子节点
+        var childrenLookup = new NullableDictionary<TKey, List<T>>();
+        var list = source as ICollection<T> ?? source.ToList();
+        foreach (var item in list.Where(item => !childrenLookup.ContainsKey(item.Id)))
+        {
+            childrenLookup[item.Id] = new List<T>();
+        }
+
+        // 构建树结构
+        foreach (var item in list.Where(item => (item.ParentId != null || !Equals(item.ParentId, default(TKey))) && childrenLookup.ContainsKey(item.ParentId ?? default)))
+        {
+            childrenLookup[item.ParentId ?? default].Add(item);
+        }
+
+        // 找到根节点,即没有父节点的节点
+        foreach (var root in list.Where(x => Equals(x.ParentId, topValue)))
+        {
+            // 为根节点和所有子节点设置Children属性
+            // 使用队列来模拟递归过程
+            var queue = new Queue<T>();
+            queue.Enqueue(root);
+            while (queue.Count > 0)
             {
-                // 为根节点和所有子节点设置Children属性
-                // 使用队列来模拟递归过程
-                var queue = new Queue<T>();
-                queue.Enqueue(root);
+                // 出队当前节点
+                var current = queue.Dequeue();
 
-                while (queue.Count > 0)
+                // 为当前节点设置子节点
+                if (childrenLookup.TryGetValue(current.Id, out var children))
                 {
-                    // 出队当前节点
-                    var current = queue.Dequeue();
-
-                    // 为当前节点设置子节点
-                    if (childrenLookup.TryGetValue(idSelector(current), out var children))
+                    current.Children = children;
+                    foreach (var child in children)
                     {
-                        current.Children = children;
-                        foreach (var child in children)
+                        // 如果子节点实现了ITreeParent接口,则设置其Parent属性
+                        if (child is ITreeParent<T> tree)
                         {
-                            // 如果子节点实现了ITreeParent接口,则设置其Parent属性
-                            if (child is ITreeParent<T> tree)
-                            {
-                                tree.Parent = current;
-                            }
-
-                            // 将子节点入队以继续处理
-                            queue.Enqueue(child);
+                            tree.Parent = current;
                         }
+
+                        // 将子节点入队以继续处理
+                        queue.Enqueue(child);
                     }
                 }
-
-                yield return root;
             }
+
+            yield return root;
         }
+    }
 
-        internal static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, TKey? topValue = default) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable
+    internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T>
+    {
+        // 创建一个字典,用于快速查找节点的子节点
+        var childrenLookup = new NullableDictionary<string, List<T>>();
+        var list = source as ICollection<T> ?? source.ToList();
+        foreach (var item in list.Where(item => !childrenLookup.ContainsKey(item.Id)))
         {
-            // 创建一个字典,用于快速查找节点的子节点
-            var childrenLookup = new NullableDictionary<TKey, List<T>>();
-            foreach (var item in source.Where(item => !childrenLookup.ContainsKey(item.Id)))
-            {
-                childrenLookup[item.Id] = new List<T>();
-            }
+            childrenLookup[item.Id] = new List<T>();
+        }
 
-            // 构建树结构
-            foreach (var item in source.Where(item => (item.ParentId != null || !Equals(item.ParentId, default(TKey))) && childrenLookup.ContainsKey(item.ParentId ?? default)))
-            {
-                childrenLookup[item.ParentId ?? default].Add(item);
-            }
+        // 构建树结构
+        foreach (var item in list.Where(item => !string.IsNullOrEmpty(item.ParentId) && childrenLookup.ContainsKey(item.ParentId)))
+        {
+            childrenLookup[item.ParentId].Add(item);
+        }
 
-            // 找到根节点,即没有父节点的节点
-            foreach (var root in source.Where(x => Equals(x.ParentId, topValue)))
+        // 找到根节点,即没有父节点的节点
+        foreach (var root in list.Where(x => Equals(x.ParentId, topValue)))
+        {
+            // 为根节点和所有子节点设置Children属性
+            // 使用队列来模拟递归过程
+            var queue = new Queue<T>();
+            queue.Enqueue(root);
+            while (queue.Count > 0)
             {
-                // 为根节点和所有子节点设置Children属性
-                // 使用队列来模拟递归过程
-                var queue = new Queue<T>();
-                queue.Enqueue(root);
+                // 出队当前节点
+                var current = queue.Dequeue();
 
-                while (queue.Count > 0)
+                // 为当前节点设置子节点
+                if (childrenLookup.TryGetValue(current.Id, out var children))
                 {
-                    // 出队当前节点
-                    var current = queue.Dequeue();
-
-                    // 为当前节点设置子节点
-                    if (childrenLookup.TryGetValue(current.Id, out var children))
+                    current.Children = children;
+                    foreach (var child in children)
                     {
-                        current.Children = children;
-                        foreach (var child in children)
+                        // 如果子节点实现了ITreeParent接口,则设置其Parent属性
+                        if (child is ITreeParent<T> tree)
                         {
-                            // 如果子节点实现了ITreeParent接口,则设置其Parent属性
-                            if (child is ITreeParent<T> tree)
-                            {
-                                tree.Parent = current;
-                            }
-
-                            // 将子节点入队以继续处理
-                            queue.Enqueue(child);
+                            tree.Parent = current;
                         }
+
+                        // 将子节点入队以继续处理
+                        queue.Enqueue(child);
                     }
                 }
-
-                yield return root;
             }
+
+            yield return root;
         }
+    }
 
-        internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T>
+    internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, T parent) where T : ITreeEntity<T>
+    {
+        // 创建一个字典,用于快速查找节点的子节点
+        var childrenLookup = new NullableDictionary<string, List<T>>();
+        var list = source as ICollection<T> ?? source.ToList();
+        foreach (var item in list.Where(item => !childrenLookup.ContainsKey(item.Id)))
         {
-            // 创建一个字典,用于快速查找节点的子节点
-            var childrenLookup = new NullableDictionary<string, List<T>>();
-            foreach (var item in source.Where(item => !childrenLookup.ContainsKey(item.Id)))
-            {
-                childrenLookup[item.Id] = new List<T>();
-            }
+            childrenLookup[item.Id] = new List<T>();
+        }
 
-            // 构建树结构
-            foreach (var item in source.Where(item => !string.IsNullOrEmpty(item.ParentId) && childrenLookup.ContainsKey(item.ParentId)))
-            {
-                childrenLookup[item.ParentId].Add(item);
-            }
+        // 构建树结构
+        foreach (var item in list.Where(item => !string.IsNullOrEmpty(item.ParentId) && childrenLookup.ContainsKey(item.ParentId)))
+        {
+            childrenLookup[item.ParentId].Add(item);
+        }
 
-            // 找到根节点,即没有父节点的节点
-            foreach (var root in source.Where(x => Equals(x.ParentId, topValue)))
+        // 找到根节点,即没有父节点的节点
+        foreach (var root in list.Where(x => x.Id == parent.Id))
+        {
+            // 为根节点和所有子节点设置Children属性
+            // 使用队列来模拟递归过程
+            var queue = new Queue<T>();
+            queue.Enqueue(root);
+            while (queue.Count > 0)
             {
-                // 为根节点和所有子节点设置Children属性
-                // 使用队列来模拟递归过程
-                var queue = new Queue<T>();
-                queue.Enqueue(root);
+                // 出队当前节点
+                var current = queue.Dequeue();
 
-                while (queue.Count > 0)
+                // 为当前节点设置子节点
+                if (childrenLookup.TryGetValue(current.Id, out var children))
                 {
-                    // 出队当前节点
-                    var current = queue.Dequeue();
-
-                    // 为当前节点设置子节点
-                    if (childrenLookup.TryGetValue(current.Id, out var children))
+                    current.Children = children;
+                    foreach (var child in children)
                     {
-                        current.Children = children;
-                        foreach (var child in children)
+                        // 如果子节点实现了ITreeParent接口,则设置其Parent属性
+                        if (child is ITreeParent<T> tree)
                         {
-                            // 如果子节点实现了ITreeParent接口,则设置其Parent属性
-                            if (child is ITreeParent<T> tree)
-                            {
-                                tree.Parent = current;
-                            }
-
-                            // 将子节点入队以继续处理
-                            queue.Enqueue(child);
+                            tree.Parent = current;
                         }
+
+                        // 将子节点入队以继续处理
+                        queue.Enqueue(child);
                     }
                 }
-                yield return root;
             }
+
+            yield return root;
         }
+    }
 
-        private static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, Func<T, TKey> idSelector, Func<T, TKey?> pidSelector, TKey? topValue = default) where T : ITreeChildren<T> where TKey : struct
+    private static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, Func<T, TKey> idSelector, Func<T, TKey?> pidSelector, TKey? topValue = default) where T : ITreeChildren<T> where TKey : struct
+    {
+        // 创建一个字典,用于快速查找节点的子节点
+        var childrenLookup = new NullableDictionary<TKey, List<T>>();
+        var list = source as ICollection<T> ?? source.ToList();
+        foreach (var item in list.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
         {
-            // 创建一个字典,用于快速查找节点的子节点
-            var childrenLookup = new NullableDictionary<TKey, List<T>>();
-            foreach (var item in source.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
-            {
-                childrenLookup[idSelector(item)] = new List<T>();
-            }
+            childrenLookup[idSelector(item)] = new List<T>();
+        }
 
-            // 构建树结构
-            foreach (var item in source.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item) ?? default)))
-            {
-                childrenLookup[pidSelector(item) ?? default].Add(item);
-            }
+        // 构建树结构
+        foreach (var item in list.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item) ?? default)))
+        {
+            childrenLookup[pidSelector(item) ?? default].Add(item);
+        }
 
-            // 找到根节点,即没有父节点的节点
-            foreach (var root in source.Where(x => Equals(pidSelector(x), topValue)))
+        // 找到根节点,即没有父节点的节点
+        foreach (var root in list.Where(x => Equals(pidSelector(x), topValue)))
+        {
+            // 为根节点和所有子节点设置Children属性
+            // 使用队列来模拟递归过程
+            var queue = new Queue<T>();
+            queue.Enqueue(root);
+            while (queue.Count > 0)
             {
-                // 为根节点和所有子节点设置Children属性
-                // 使用队列来模拟递归过程
-                var queue = new Queue<T>();
-                queue.Enqueue(root);
+                // 出队当前节点
+                var current = queue.Dequeue();
 
-                while (queue.Count > 0)
+                // 为当前节点设置子节点
+                if (childrenLookup.TryGetValue(idSelector(current), out var children))
                 {
-                    // 出队当前节点
-                    var current = queue.Dequeue();
-
-                    // 为当前节点设置子节点
-                    if (childrenLookup.TryGetValue(idSelector(current), out var children))
+                    current.Children = children;
+                    foreach (var child in children)
                     {
-                        current.Children = children;
-                        foreach (var child in children)
+                        // 如果子节点实现了ITreeParent接口,则设置其Parent属性
+                        if (child is ITreeParent<T> tree)
                         {
-                            // 如果子节点实现了ITreeParent接口,则设置其Parent属性
-                            if (child is ITreeParent<T> tree)
-                            {
-                                tree.Parent = current;
-                            }
-
-                            // 将子节点入队以继续处理
-                            queue.Enqueue(child);
+                            tree.Parent = current;
                         }
+
+                        // 将子节点入队以继续处理
+                        queue.Enqueue(child);
                     }
                 }
-                yield return root;
             }
+
+            yield return root;
+        }
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <typeparam name="TKey"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="idSelector"></param>
+    /// <param name="pidSelector"></param>
+    /// <param name="topValue">根对象parentId的值</param>
+    /// <returns></returns>
+    public static List<Tree<T>> ToTreeGeneral<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey>> pidSelector, TKey topValue = default) where TKey : IComparable
+    {
+        if (idSelector.Body.ToString() == pidSelector.Body.ToString())
+        {
+            throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+        }
+
+        var pidFunc = pidSelector.Compile();
+        var idFunc = idSelector.Compile();
+        var list = source.Where(t => t != null).ToList();
+        var temp = new List<Tree<T>>();
+        foreach (var item in list.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
+        {
+            var parent = new Tree<T>(item);
+            temp.AddRange(BuildTree(list, parent, idFunc, pidFunc));
+        }
+
+        return temp;
+    }
+
+    private static IEnumerable<Tree<T>> BuildTree<T, TKey>(List<T> list, Tree<T> parent, Func<T, TKey> idSelector, Func<T, TKey> pidSelector) where TKey : IComparable
+    {
+        // 创建一个字典,用于快速查找节点的子节点
+        var childrenLookup = new Dictionary<TKey, List<Tree<T>>>();
+        foreach (var item in list.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
+        {
+            childrenLookup[idSelector(item)] = new List<Tree<T>>();
         }
 
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <typeparam name="TKey"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="idSelector"></param>
-        /// <param name="pidSelector"></param>
-        /// <param name="topValue">根对象parentId的值</param>
-        /// <returns></returns>
-        public static List<Tree<T>> ToTreeGeneral<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey>> pidSelector, TKey topValue = default) where TKey : IComparable
+        // 构建树结构
+        foreach (var item in list.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item))))
         {
-            if (idSelector.Body.ToString() == pidSelector.Body.ToString())
+            childrenLookup[pidSelector(item)].Add(new Tree<T>(item));
+        }
+
+        // 找到根节点,即没有父节点的节点
+        foreach (var root in list.Where(x => Equals(pidSelector(x), idSelector(parent.Value))))
+        {
+            // 为根节点和所有子节点设置Children属性
+            // 使用队列来模拟递归过程
+            var queue = new Queue<Tree<T>>();
+            queue.Enqueue(new Tree<T>(root));
+
+            while (queue.Count > 0)
             {
-                throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+                // 出队当前节点
+                var current = queue.Dequeue();
+
+                // 为当前节点设置子节点
+                if (childrenLookup.TryGetValue(idSelector(current.Value), out var children))
+                {
+                    current.Children = children;
+                    foreach (var child in children)
+                    {
+                        child.Parent = current.Parent;
+                        // 将子节点入队以继续处理
+                        queue.Enqueue(child);
+                    }
+                }
             }
 
-            var pidFunc = pidSelector.Compile();
-            var idFunc = idSelector.Compile();
-            source = source.Where(t => t != null);
-            var temp = new List<Tree<T>>();
-            foreach (var item in source.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
+            yield return new Tree<T>(root);
+        }
+    }
+
+    /// <summary>
+    /// 所有子级
+    /// </summary>
+    public static ICollection<T> AllChildren<T>(this T tree) where T : ITreeChildren<T> => GetChildren(tree, c => c.Children);
+
+    /// <summary>
+    /// 所有子级
+    /// </summary>
+    public static ICollection<T> AllChildren<T>(this T tree, Func<T, IEnumerable<T>> selector) where T : ITreeChildren<T> => GetChildren(tree, selector);
+
+    /// <summary>
+    /// 所有子级
+    /// </summary>
+    public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree) => GetChildren(tree, c => c.Children);
+
+    /// <summary>
+    /// 所有子级
+    /// </summary>
+    public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree, Func<Tree<T>, IEnumerable<Tree<T>>> selector) => GetChildren(tree, selector);
+
+    /// <summary>
+    /// 所有父级
+    /// </summary>
+    public static List<T> AllParent<T>(this T tree) where T : class, ITreeParent<T> => GetParents(tree, c => c.Parent);
+
+    /// <summary>
+    /// 所有父级
+    /// </summary>
+    public static List<T> AllParent<T>(this T tree, Func<T, T> selector) where T : class, ITreeParent<T> => GetParents(tree, selector);
+
+    /// <summary>
+    /// 所有父级
+    /// </summary>
+    public static List<Tree<T>> AllParent<T>(this Tree<T> tree, Func<Tree<T>, Tree<T>> selector) => GetParents(tree, selector);
+
+    /// <summary>
+    /// 是否是根节点
+    /// </summary>
+    public static bool IsRoot<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => tree.Parent == null;
+
+    /// <summary>
+    /// 是否是叶子节点
+    /// </summary>
+    public static bool IsLeaf<T>(this ITreeChildren<T> tree) where T : ITreeChildren<T> => tree.Children?.Count == 0;
+
+    /// <summary>
+    /// 是否是根节点
+    /// </summary>
+    public static bool IsRoot<T>(this Tree<T> tree) => tree.Parent == null;
+
+    /// <summary>
+    /// 是否是叶子节点
+    /// </summary>
+    public static bool IsLeaf<T>(this Tree<T> tree) => tree.Children?.Count == 0;
+
+    /// <summary>
+    /// 深度层级
+    /// </summary>
+    public static int Level<T>(this T tree) where T : class, ITreeParent<T>
+    {
+        if (tree == null)
+        {
+            throw new ArgumentNullException(nameof(tree), "当前节点不能为null");
+        }
+
+        // 使用一个队列来存储待处理的节点
+        var queue = new Queue<T>();
+        queue.Enqueue(tree);
+        int level = 1;
+
+        // 循环直到队列为空
+        while (queue.Count > 0)
+        {
+            int nodeCount = queue.Count; // 当前层级的节点数
+
+            for (int i = 0; i < nodeCount; i++)
             {
-                var parent = new Tree<T>(item);
-                BuildTree(source, parent, idFunc, pidFunc);
-                temp.Add(parent);
+                // 从队列中出队一个节点
+                T currentNode = queue.Dequeue();
+
+                // 如果当前节点是根节点,则返回当前层级
+                if (currentNode.Parent == null)
+                {
+                    return level;
+                }
+
+                // 将当前节点的父节点入队
+                if (currentNode.Parent != null)
+                {
+                    queue.Enqueue(currentNode.Parent);
+                }
             }
 
-            return temp;
+            // 完成当前层级的遍历,准备进入下一层级
+            level++;
         }
 
-        private static void BuildTree<T, TKey>(IEnumerable<T> source, Tree<T> parent, Func<T, TKey> idSelector, Func<T, TKey> pidSelector) where TKey : IComparable
+        // 如果执行到这里,说明没有找到根节点
+        throw new InvalidOperationException("未找到根节点");
+    }
+
+    /// <summary>
+    /// 节点路径(UNIX路径格式,以“/”分隔)
+    /// </summary>
+    public static string Path<T>(this T tree) where T : class, ITree<T> => GetFullPath(tree, t => t.Name);
+
+    /// <summary>
+    /// 节点路径(UNIX路径格式,以“/”分隔)
+    /// </summary>
+    public static string Path<T>(this T tree, Func<T, string> selector) where T : class, ITreeParent<T> => GetFullPath(tree, selector);
+
+    /// <summary>
+    /// 节点路径
+    /// </summary>
+    /// <param name="tree"></param>
+    /// <param name="separator">分隔符</param>
+    public static string Path<T>(this T tree, string separator) where T : class, ITree<T> => GetFullPath(tree, t => t.Name, separator);
+
+    /// <summary>
+    /// 节点路径
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="tree"></param>
+    /// <param name="selector">选择字段</param>
+    /// <param name="separator">分隔符</param>
+    /// <returns></returns>
+    public static string Path<T>(this T tree, Func<T, string> selector, string separator) where T : class, ITreeParent<T> => GetFullPath(tree, selector, separator);
+
+    /// <summary>
+    /// 根节点
+    /// </summary>
+    public static T Root<T>(this T tree) where T : class, ITreeParent<T> => GetRoot(tree, t => t.Parent);
+
+    private static string GetFullPath<T>(T c, Func<T, string> selector, string separator = "/") where T : class, ITreeParent<T>
+    {
+        if (c == null || selector == null)
+        {
+            throw new ArgumentNullException(c == null ? nameof(c) : nameof(selector), "当前节点或选择器不能为null");
+        }
+
+        // 使用一个栈来存储节点,栈将逆序存储路径中的节点
+        var stack = new Stack<T>();
+        stack.Push(c);
+        var currentNode = c;
+        while (currentNode != null)
+        {
+            stack.Push(currentNode);
+            currentNode = currentNode.Parent;
+        }
+
+        // 构建路径字符串
+        return stack.Select(selector).Join(separator);
+    }
+
+    /// <summary>
+    /// 根节点
+    /// </summary>
+    public static T GetRoot<T>(T c, Func<T, T> selector) where T : class, ITreeParent<T>
+    {
+        if (c == null || selector == null)
+        {
+            throw new ArgumentNullException(c == null ? nameof(c) : nameof(selector), "当前节点或父级选择器不能为null");
+        }
+
+        // 使用一个集合来存储已访问的节点,以避免无限循环
+        var visited = new HashSet<T>();
+        T currentNode = c;
+
+        // 向上遍历直到找到根节点
+        while (currentNode != null)
         {
-            var temp = new List<Tree<T>>();
-            foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent.Value)) == true))
+            // 如果当前节点已被访问,说明存在循环引用,抛出异常
+            if (!visited.Add(currentNode))
             {
-                var p = new Tree<T>(item);
-                BuildTree(source, p, idSelector, pidSelector);
-                p.Parent = parent.Value;
-                temp.Add(p);
+                throw new InvalidOperationException("节点存在循环引用");
             }
 
-            parent.Children = temp;
-        }
-
-        /// <summary>
-        /// 所有子级
-        /// </summary>
-        public static ICollection<T> AllChildren<T>(this T tree) where T : ITreeChildren<T> => GetChildren(tree, c => c.Children);
-
-        /// <summary>
-        /// 所有子级
-        /// </summary>
-        public static ICollection<T> AllChildren<T>(this T tree, Func<T, IEnumerable<T>> selector) where T : ITreeChildren<T> => GetChildren(tree, selector);
-
-        /// <summary>
-        /// 所有子级
-        /// </summary>
-        public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree) => GetChildren(tree, c => c.Children);
-
-        /// <summary>
-        /// 所有子级
-        /// </summary>
-        public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree, Func<Tree<T>, IEnumerable<Tree<T>>> selector) => GetChildren(tree, selector);
-
-        /// <summary>
-        /// 所有父级
-        /// </summary>
-        public static ICollection<T> AllParent<T>(this T tree) where T : ITreeParent<T> => GetParents(tree, c => c.Parent);
-
-        /// <summary>
-        /// 所有父级
-        /// </summary>
-        public static ICollection<T> AllParent<T>(this T tree, Func<T, T> selector) where T : ITreeParent<T> => GetParents(tree, selector);
-
-        /// <summary>
-        /// 所有父级
-        /// </summary>
-        public static ICollection<Tree<T>> AllParent<T>(this Tree<T> tree, Func<Tree<T>, Tree<T>> selector) => GetParents(tree, selector);
-
-        /// <summary>
-        /// 是否是根节点
-        /// </summary>
-        public static bool IsRoot<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => tree.Parent == null;
-
-        /// <summary>
-        /// 是否是叶子节点
-        /// </summary>
-        public static bool IsLeaf<T>(this ITreeChildren<T> tree) where T : ITreeChildren<T> => tree.Children?.Count == 0;
-
-        /// <summary>
-        /// 是否是根节点
-        /// </summary>
-        public static bool IsRoot<T>(this Tree<T> tree) => tree.Parent == null;
-
-        /// <summary>
-        /// 是否是叶子节点
-        /// </summary>
-        public static bool IsLeaf<T>(this Tree<T> tree) => tree.Children?.Count == 0;
-
-        /// <summary>
-        /// 深度层级
-        /// </summary>
-        public static int Level<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => IsRoot(tree) ? 1 : Level(tree.Parent) + 1;
-
-        /// <summary>
-        /// 节点路径(UNIX路径格式,以“/”分隔)
-        /// </summary>
-        public static string Path<T>(this T tree) where T : ITree<T> => GetFullPath(tree, t => t.Name);
-
-        /// <summary>
-        /// 节点路径(UNIX路径格式,以“/”分隔)
-        /// </summary>
-        public static string Path<T>(this T tree, Func<T, string> selector) where T : ITreeParent<T> => GetFullPath(tree, selector);
-
-        /// <summary>
-        /// 节点路径
-        /// </summary>
-        /// <param name="tree"></param>
-        /// <param name="separator">分隔符</param>
-        public static string Path<T>(this T tree, string separator) where T : ITree<T> => GetFullPath(tree, t => t.Name, separator);
-
-        /// <summary>
-        /// 节点路径
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="tree"></param>
-        /// <param name="selector">选择字段</param>
-        /// <param name="separator">分隔符</param>
-        /// <returns></returns>
-        public static string Path<T>(this T tree, Func<T, string> selector, string separator) where T : ITreeParent<T> => GetFullPath(tree, selector, separator);
-
-        /// <summary>
-        /// 根节点
-        /// </summary>
-        public static T Root<T>(this T tree) where T : ITreeParent<T> => GetRoot(tree, t => t.Parent);
-
-        private static string GetFullPath<T>(T c, Func<T, string> selector, string separator = "/") where T : ITreeParent<T> => c.Parent != null ? GetFullPath(c.Parent, selector, separator) + separator + selector(c) : selector(c);
-
-        /// <summary>
-        /// 根节点
-        /// </summary>
-        public static T GetRoot<T>(T c, Func<T, T> selector) where T : ITreeParent<T> => c.Parent != null ? GetRoot(c.Parent, selector) : c;
-
-        /// <summary>
-        /// 递归取出所有下级
-        /// </summary>
-        /// <param name="t"></param>
-        /// <param name="selector"></param>
-        /// <returns></returns>
-        private static List<T> GetChildren<T>(T t, Func<T, IEnumerable<T>> selector)
-        {
-            return selector(t).Union(selector(t).Where(c => selector(c)?.Any() == true).SelectMany(c => GetChildren(c, selector))).ToList();
-        }
-
-        /// <summary>
-        /// 递归取出所有上级
-        /// </summary>
-        /// <param name="t"></param>
-        /// <returns></returns>
-        private static List<T> GetParents<T>(T t, Func<T, T> selector)
-        {
-            var list = new List<T>() { selector(t) };
-            if (selector(t) != null)
+            var parent = selector(currentNode);
+            if (parent == null)
             {
-                return list.Union(GetParents(selector(t), selector)).Where(x => x != null).ToList();
+                // 找到了根节点
+                return currentNode;
             }
 
-            list.RemoveAll(x => x == null);
-            return list;
+            currentNode = parent;
         }
+
+        // 如果currentNode为null,说明最初的节点c就是根节点
+        return c;
     }
 
-    public static class TreeExtensionLong
+    /// <summary>
+    /// 递归取出所有下级
+    /// </summary>
+    /// <param name="t"></param>
+    /// <param name="selector"></param>
+    /// <returns></returns>
+    private static List<T> GetChildren<T>(T t, Func<T, IEnumerable<T>> selector)
     {
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source) where T : ITreeEntity<T, long>
+        if (t == null || selector == null)
         {
-            return source.ToTree<T, long>();
+            return new List<T>(); // 如果t或selector为null,则返回空列表
         }
-    }
 
-    public static class TreeExtensionGuid
-    {
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source) where T : ITreeEntity<T, Guid>
+        var list = new List<T>();
+        var queue = new Queue<T>();
+        queue.Enqueue(t);
+        while (queue.Count > 0)
         {
-            return source.ToTree<T, Guid>();
+            var current = queue.Dequeue();
+            list.Add(current); // 将当前节点添加到结果列表
+            var children = selector(current) ?? new List<T>();
+            foreach (var child in children)
+            {
+                // 只有当子节点还有自己的子节点时,才将其加入队列
+                if (selector(child).Any())
+                {
+                    queue.Enqueue(child);
+                }
+            }
         }
+
+        return list;
     }
 
-    public static class TreeExtensionString
+    /// <summary>
+    /// 递归取出所有上级
+    /// </summary>
+    /// <param name="t"></param>
+    /// <param name="selector"></param>
+    /// <returns></returns>
+    private static List<T> GetParents<T>(T t, Func<T, T> selector) where T : class
     {
-        /// <summary>
-        /// 平行集合转换成树形结构
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="source"></param>
-        /// <param name="topValue"></param>
-        /// <returns></returns>
-        public static List<T> ToTree<T>(this IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T>
+        if (t == null || selector == null)
         {
-            if (source is IQueryable<T> queryable)
+            return new List<T>(); // 如果t或selector为null,则返回空列表
+        }
+
+        var parents = new List<T>();
+        var current = t;
+        while (current != null)
+        {
+            // 添加当前节点到父节点列表
+            parents.Add(current);
+
+            // 通过selector函数获取当前节点的父节点
+            current = selector(current);
+
+            // 如果selector返回了已经遍历过的节点,则停止遍历以避免无限循环
+            if (parents.Contains(current))
             {
-                source = queryable.ToList();
+                break;
             }
+        }
+
+        // 由于是逆序添加的,所以需要反转列表
+        parents.Reverse();
+        return parents;
+    }
+}
+
+public static class TreeExtensionLong
+{
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T, long>
+    {
+        return source.ToTree<T, long>();
+    }
+}
+
+public static class TreeExtensionGuid
+{
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T, Guid>
+    {
+        return source.ToTree<T, Guid>();
+    }
+}
 
-            source = source.Where(t => t != null).ToList();
-            return TreeExtensions.BuildTree(source, topValue).ToList();
+public static class TreeExtensionString
+{
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <param name="topValue"></param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source, string topValue) where T : class, ITreeEntity<T>
+    {
+        if (source is IQueryable<T> queryable)
+        {
+            source = queryable.ToList();
         }
+
+        source = source.Where(t => t != null).ToList();
+        return TreeExtensions.BuildTree(source, topValue).ToList();
+    }
+
+    /// <summary>
+    /// 平行集合转换成树形结构
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="source"></param>
+    /// <returns></returns>
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T>
+    {
+        if (source is IQueryable<T> queryable)
+        {
+            source = queryable.ToList();
+        }
+
+        source = source.Where(t => t != null).ToList();
+        return source.Where(t => string.IsNullOrEmpty(t.ParentId)).SelectMany(parent => TreeExtensions.BuildTree(source, parent)).ToList();
     }
 }

+ 1 - 1
Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj

@@ -18,7 +18,7 @@
         <Product>Masuit.Tools.AspNetCore</Product>
         <PackageId>Masuit.Tools.AspNetCore</PackageId>
         <LangVersion>latest</LangVersion>
-        <Version>2024.3.2</Version>
+        <Version>2024.3.3</Version>
         <RepositoryType></RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
         <FileVersion>1.1.9</FileVersion>

+ 1 - 1
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -6,7 +6,7 @@
 官网教程:https://tools.masuit.org
 github:https://github.com/ldqk/Masuit.Tools
         </Description>
-        <Version>2024.3.2</Version>
+        <Version>2024.3.3</Version>
         <Copyright>Copyright © 懒得勤快</Copyright>
         <PackageProjectUrl>https://github.com/ldqk/Masuit.Tools</PackageProjectUrl>
         <PackageTags>Masuit.Tools,工具库,Utility,Crypt,Extensions</PackageTags>

+ 1 - 1
Masuit.Tools.Excel/Masuit.Tools.Excel.csproj

@@ -3,7 +3,7 @@
         <TargetFramework>netstandard2.0</TargetFramework>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>2024.3.2</Version>
+        <Version>2024.3.3</Version>
         <Authors>懒得勤快</Authors>
         <Description>Masuit.Tools.Excel导出库,支持一些简单数据的导出,支持图片列</Description>
         <Copyright>懒得勤快</Copyright>

+ 1 - 1
Masuit.Tools.Net45/package.nuspec

@@ -2,7 +2,7 @@
 <package>
     <metadata>
         <id>Masuit.Tools.Net45</id>
-        <version>2024.3.2</version>
+        <version>2024.3.3</version>
         <title>Masuit.Tools</title>
         <authors>懒得勤快</authors>
         <owners>masuit.com</owners>

+ 1 - 1
Masuit.Tools/package.nuspec

@@ -2,7 +2,7 @@
 <package>
     <metadata>
         <id>Masuit.Tools.Net</id>
-        <version>2024.3.2</version>
+        <version>2024.3.3</version>
         <title>Masuit.Tools</title>
         <authors>懒得勤快</authors>
         <owners>masuit.com</owners>

+ 22 - 3
Test/Masuit.Tools.Abstractions.Test/Tree/TreeTest.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Linq;
 using Masuit.Tools.Models;
 using Xunit;
@@ -51,6 +52,15 @@ public class TreeTest
         Assert.Equal(tree[0].Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Id, 8);
         Assert.Equal(tree.Count, 2);
         Assert.Equal(tree[0].AllChildren().Count, 1498);
+        var a = tree.Filter(c => c.Id == 39999).ToList();
+        Assert.Equal(a[0].Id, 39999);
+        var raw = tree.Flatten().ToList();
+        Assert.Equal(raw.Count, list.Count);
+        var allParent = a[0].AllParent();
+        Assert.Equal(allParent[0].AllChildren().Count, 19999);
+        Assert.Equal(a[0].Root(), list[1]);
+        Assert.StartsWith("Root", a[0].Path());
+        Assert.Equal(a[0].Level(), 20000);
     }
 
     [Fact]
@@ -67,7 +77,7 @@ public class TreeTest
             new MyClass2
             {
                 Name = "Root",
-                Id = "2000"
+                Id = "20000"
             }
         };
         for (int i = 2; i < 1500; i++)
@@ -80,7 +90,7 @@ public class TreeTest
             });
         }
 
-        for (int i = 2001; i < 4000; i++)
+        for (int i = 20001; i < 40000; i++)
         {
             list.Add(new MyClass2
             {
@@ -97,6 +107,15 @@ public class TreeTest
         Assert.Equal(tree[0].Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Children.FirstOrDefault().Id, "8");
         Assert.Equal(tree.Count, 2);
         Assert.Equal(tree[0].AllChildren().Count, 1498);
+        var a = tree.Filter(c => c.Id == "39999").ToList();
+        Assert.Equal(a[0].Id, "39999");
+        var raw = tree.Flatten().ToList();
+        Assert.Equal(raw.Count, list.Count);
+        var allParent = a[0].AllParent();
+        Assert.Equal(allParent[0].AllChildren().Count, 19999);
+        Assert.Equal(a[0].Root(), list[1]);
+        Assert.StartsWith("Root", a[0].Path());
+        Assert.Equal(a[0].Level(), 20000);
     }
 }