瀏覽代碼

优化CompareChangesPlus

懒得勤快 11 月之前
父節點
當前提交
83fbec8b40

+ 7 - 14
Masuit.Tools.Abstractions/Extensions/BaseType/IEnumerableExtensions.cs

@@ -1311,14 +1311,7 @@ public static class IEnumerableExtensions
     /// <returns></returns>
     public static (List<T> adds, List<T> remove, List<(T first, T second)> updates) CompareChangesPlus<T, TKey>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, TKey> keySelector)
     {
-        first ??= new List<T>();
-        second ??= new List<T>();
-        var firstSource = first as ICollection<T> ?? first.ToList();
-        var secondSource = second as ICollection<T> ?? second.ToList();
-        var add = firstSource.ExceptBy(secondSource, keySelector).ToList();
-        var remove = secondSource.ExceptBy(firstSource, keySelector).ToList();
-        var updates = firstSource.IntersectBy(secondSource, keySelector).Select(t1 => (t1, secondSource.FirstOrDefault(t2 => keySelector(t1).Equals(keySelector(t2))))).ToList();
-        return (add, remove, updates);
+        return CompareChangesPlus(first, second, keySelector, keySelector);
     }
 
     /// <summary>
@@ -1356,17 +1349,17 @@ public static class IEnumerableExtensions
     {
         first ??= new List<T1>();
         second ??= new List<T2>();
-        var firstDict = first.ToLookup(firstKeySelector);
-        var secondDict = second.ToLookup(secondKeySelector);
+        var lookup1 = first.ToLookup(firstKeySelector);
+        var lookup2 = second.ToLookup(secondKeySelector);
         var add = new List<T1>();
         var remove = new List<T2>();
         var updates = new List<(T1 first, T2 second)>();
 
-        foreach (var x in firstDict)
+        foreach (var x in lookup1)
         {
-            if (secondDict.Contains(x.Key))
+            if (lookup2.Contains(x.Key))
             {
-                updates.Add((x.First(), secondDict[x.Key].First()));
+                updates.Add((x.First(), lookup2[x.Key].First()));
             }
             else
             {
@@ -1374,7 +1367,7 @@ public static class IEnumerableExtensions
             }
         }
 
-        foreach (var x in secondDict.Where(x => !firstDict.Contains(x.Key)))
+        foreach (var x in lookup2.Where(x => !lookup1.Contains(x.Key)))
         {
             remove.AddRange(x);
         }

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

@@ -48,7 +48,7 @@
 
     <ItemGroup>
         <PackageReference Include="AngleSharp" Version="1.1.2" />
-        <PackageReference Include="AngleSharp.Css" Version="1.0.0-beta.139" />
+        <PackageReference Include="AngleSharp.Css" Version="1.0.0-beta.144" />
         <PackageReference Include="DnsClient" Version="1.8.0" />
         <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
         <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />

+ 50 - 110
Masuit.Tools.Abstractions/Models/TreeExtensions.cs

@@ -3,6 +3,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 #endif
+
 using System.Linq.Expressions;
 using Masuit.Tools.Systems;
 
@@ -20,8 +21,7 @@ public static class TreeExtensions
     /// <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> 
-        => Flatten(items).Where(func);
+    public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Func<T, bool> func) where T : class, ITreeChildren<T> => Flatten(items).Where(func);
 
     /// <summary>
     /// 过滤
@@ -30,8 +30,7 @@ public static class TreeExtensions
     /// <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 
-        => Flatten(items).Where(func);
+    public static IEnumerable<Tree<T>> Filter<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, bool> func) where T : class => Flatten(items).Where(func);
 
     /// <summary>
     /// 过滤
@@ -40,8 +39,7 @@ public static class TreeExtensions
     /// <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> 
-        => Flatten(item).Where(func);
+    public static IEnumerable<T> Filter<T>(this T item, Func<T, bool> func) where T : class, ITreeChildren<T> => Flatten(item).Where(func);
 
     /// <summary>
     /// 过滤
@@ -50,8 +48,7 @@ public static class TreeExtensions
     /// <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 
-        => Flatten(item).Where(func);
+    public static IEnumerable<Tree<T>> Filter<T>(this Tree<T> item, Func<Tree<T>, bool> func) where T : class => Flatten(item).Where(func);
 
     /// <summary>
     /// 平铺开
@@ -60,9 +57,7 @@ public static class TreeExtensions
     /// <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>
-        => items.Flatten(i => i.Children ?? [], optionAction);
+    public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Action<T, T> optionAction = null) where T : class, ITreeChildren<T> => items.Flatten(i => i.Children ?? [], optionAction);
 
     /// <summary>
     /// 平铺开
@@ -71,10 +66,7 @@ public static class TreeExtensions
     /// <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>
-        => p != null
-            ? Flatten([p], t => t.Children, optionAction)
-            : [];
+    public static IEnumerable<T> Flatten<T>(this T p, Action<T, T> optionAction = null) where T : class, ITreeChildren<T> => p != null ? Flatten([p], t => t.Children, optionAction) : [];
 
     /// <summary>
     /// 平铺开任意树形结构数据
@@ -124,11 +116,7 @@ public static class TreeExtensions
     /// <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
-        => items != null
-            ? Flatten(items, t => t.Children, optionAction)
-            : [];
+    public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Action<Tree<T>, Tree<T>> optionAction = null) where T : class => items != null ? Flatten(items, t => t.Children, optionAction) : [];
 
     /// <summary>
     /// 平铺开
@@ -156,8 +144,7 @@ public static class TreeExtensions
     /// <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 = null) where T : ITreeParent<T>, ITreeChildren<T>
-        => ToTree<T, string>(source, idSelector, pidSelector, topValue);
+    public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, string>> idSelector, Expression<Func<T, string>> pidSelector, string topValue = null) where T : ITreeParent<T>, ITreeChildren<T> => ToTree<T, string>(source, idSelector, pidSelector, topValue);
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -168,8 +155,7 @@ public static class TreeExtensions
     /// <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>
-        => ToTree<T, int>(source, idSelector, pidSelector, topValue);
+    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> => ToTree<T, int>(source, idSelector, pidSelector, topValue);
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -180,8 +166,7 @@ public static class TreeExtensions
     /// <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>
-        =>ToTree<T, long>(source, idSelector, pidSelector, topValue);
+    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> => ToTree<T, long>(source, idSelector, pidSelector, topValue);
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -192,8 +177,7 @@ public static class TreeExtensions
     /// <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>
-        =>ToTree<T, Guid>(source, idSelector, pidSelector, topValue);
+    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> => ToTree<T, Guid>(source, idSelector, pidSelector, topValue);
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -205,10 +189,7 @@ public static class TreeExtensions
     /// <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
-        => idSelector.Body.ToString() != pidSelector.Body.ToString()
-            ? BuildTree(source.Enumerable2NonNullList(), idSelector.Compile(), pidSelector.Compile(), topValue).ToList()
-            : throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+    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 => idSelector.Body.ToString() != pidSelector.Body.ToString() ? BuildTree(source.Enumerable2NonNullList(), idSelector.Compile(), pidSelector.Compile(), topValue).ToList() : throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -216,8 +197,7 @@ public static class TreeExtensions
     /// <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>
-        =>ToTree<T, int>(source);
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T, int> => ToTree<T, int>(source);
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -227,8 +207,7 @@ public static class TreeExtensions
     /// <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 
-        => BuildTree(source.Enumerable2NonNullList(), topValue).ToList();
+    public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, TKey? topValue = null) where T : class, ITreeEntity<T, TKey> where TKey : struct, IComparable => BuildTree(source.Enumerable2NonNullList(), topValue).ToList();
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -240,10 +219,7 @@ public static class TreeExtensions
     /// <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 = null) where T : ITreeChildren<T> where TKey : struct
-        => idSelector.Body.ToString() != pidSelector.Body.ToString()
-            ? BuildTree(source.Enumerable2NonNullList(), idSelector.Compile(), pidSelector.Compile(), topValue).ToList()
-            : throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+    public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey?>> pidSelector, TKey? topValue = null) where T : ITreeChildren<T> where TKey : struct => idSelector.Body.ToString() != pidSelector.Body.ToString() ? BuildTree(source.Enumerable2NonNullList(), idSelector.Compile(), pidSelector.Compile(), topValue).ToList() : throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
 
     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
     {
@@ -295,11 +271,9 @@ public static class TreeExtensions
         }
     }
 
-    internal static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, TKey? topValue = null) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable 
-        => BuildTree(source, t => t.Id, t => t.ParentId, topValue);
+    internal static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, TKey? topValue = null) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable => BuildTree(source, t => t.Id, t => t.ParentId, topValue);
 
-    internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T> 
-        => BuildTree(source, t => t.Id, t => t.ParentId, topValue);
+    internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T> => BuildTree(source, t => t.Id, t => t.ParentId, topValue);
 
     internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, T parent) where T : ITreeEntity<T>
     {
@@ -405,14 +379,7 @@ public static class TreeExtensions
     /// <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
-        => idSelector.Body.ToString() != pidSelector.Body.ToString()
-            ? BuildTreeGeneral(
-                source.Where(t => t != null).ToList(), 
-                idSelector.Compile(), 
-                pidSelector.Compile(),
-                topValue).ToList()
-            : throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
+    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 => idSelector.Body.ToString() != pidSelector.Body.ToString() ? BuildTreeGeneral(source.Where(t => t != null).ToList(), idSelector.Compile(), pidSelector.Compile(), topValue).ToList() : throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
 
     private static IEnumerable<Tree<T>> BuildTreeGeneral<T, TKey>(List<T> list, Func<T, TKey> idSelector, Func<T, TKey> pidSelector, TKey parent) where TKey : IComparable
     {
@@ -461,68 +428,57 @@ public static class TreeExtensions
     /// <summary>
     /// 所有子级
     /// </summary>
-    public static ICollection<T> AllChildren<T>(this T tree) where T : ITreeChildren<T> 
-        => GetChildren(tree, c => c.Children);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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;
+    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;
+    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;
+    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;
+    public static bool IsLeaf<T>(this Tree<T> tree) => tree.Children?.Count == 0;
 
     /// <summary>
     /// 深度层级
@@ -567,14 +523,12 @@ public static class TreeExtensions
     /// <summary>
     /// 节点路径(UNIX路径格式,以“/”分隔)
     /// </summary>
-    public static string Path<T>(this T tree) where T : class, ITree<T> 
-        => GetFullPath(tree, t => t.Name);
+    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);
+    public static string Path<T>(this T tree, Func<T, string> selector) where T : class, ITreeParent<T> => GetFullPath(tree, selector);
 
     /// <summary>
     /// 节点路径
@@ -591,14 +545,12 @@ public static class TreeExtensions
     /// <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);
+    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);
+    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>
     {
@@ -642,10 +594,12 @@ public static class TreeExtensions
                 throw new InvalidOperationException("节点存在循环引用");
 
             var parent = selector(currentNode);
-            if (parent != null)
-                currentNode = parent;
-            else
-                return currentNode;// 找到了根节点
+            if (parent == null)
+            {
+                return currentNode; // 找到了根节点
+            }
+
+            currentNode = parent;
         }
     }
 
@@ -668,13 +622,9 @@ public static class TreeExtensions
             var current = queue.Dequeue();
             list.Add(current); // 将当前节点添加到结果列表
             var children = selector(current) ?? new List<T>();
-            foreach (var child in children)
+            foreach (var child in children.Where(child => selector(child).Any()))
             {
-                // 只有当子节点还有自己的子节点时,才将其加入队列
-                if (selector(child).Any())
-                {
-                    queue.Enqueue(child);
-                }
+                queue.Enqueue(child);
             }
         }
 
@@ -726,8 +676,7 @@ public static class TreeExtensionLong
     /// <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> 
-        => source.ToTree<T, long>();
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T, long> => source.ToTree<T, long>();
 }
 
 /// <summary>
@@ -741,8 +690,7 @@ public static class TreeExtensionGuid
     /// <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> 
-        => source.ToTree<T, Guid>();
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T, Guid> => source.ToTree<T, Guid>();
 }
 
 /// <summary>
@@ -757,8 +705,7 @@ public static class TreeExtensionString
     /// <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> 
-        => TreeExtensions.BuildTree(source.Enumerable2NonNullList(), topValue).ToList();
+    public static List<T> ToTree<T>(this IEnumerable<T> source, string topValue) where T : class, ITreeEntity<T> => TreeExtensions.BuildTree(source.Enumerable2NonNullList(), topValue).ToList();
 
     /// <summary>
     /// 平行集合转换成树形结构
@@ -766,12 +713,10 @@ public static class TreeExtensionString
     /// <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>
-        => source.Enumerable2NonNullList()
-        .Where(t => string.IsNullOrEmpty(t.ParentId))
-        .SelectMany(parent => TreeExtensions.BuildTree(source, parent)).ToList();
+    public static List<T> ToTree<T>(this IEnumerable<T> source) where T : class, ITreeEntity<T> => source.Enumerable2NonNullList().Where(t => string.IsNullOrEmpty(t.ParentId)).SelectMany(parent => TreeExtensions.BuildTree(source, parent)).ToList();
 }
-file static class TreeExtensionCommon 
+
+internal static class TreeExtensionCommon
 {
     /// <summary>
     /// 将IEnumerable转换成不含null的List,若T为IQueryable,则将数据读取到内存
@@ -781,12 +726,7 @@ file static class TreeExtensionCommon
     /// <returns></returns>
     public static List<T> Enumerable2NonNullList<T>(this IEnumerable<T> source)
     {
-        source = source is IQueryable<T> queryable 
-            ? queryable.AsEnumerable() 
-            : source;
-        return (typeof(T).IsValueType
-                ? source
-                : source.Where(t => t != null))
-            .ToList();
+        source = source is IQueryable<T> queryable ? queryable.AsEnumerable() : source;
+        return (typeof(T).IsValueType ? source : source.Where(t => t != null)).ToList();
     }
 }

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

@@ -44,7 +44,7 @@
 
     <ItemGroup>
         <FrameworkReference Include="Microsoft.AspNetCore.App" />
-        <PackageReference Include="FastExpressionCompiler" Version="5.0.0" />
+        <PackageReference Include="FastExpressionCompiler" Version="5.0.1" />
     </ItemGroup>
 
     <ItemGroup>

+ 4 - 0
Test/Masuit.Tools.Abstractions.Test/Tree/TreeTest.cs

@@ -61,6 +61,8 @@ public class TreeTest
         Assert.Equal(a[0].Root(), list[1]);
         Assert.StartsWith("Root", a[0].Path());
         Assert.Equal(a[0].Level(), 20000);
+        Assert.True(tree[0].IsRoot());
+        Assert.True(list[1499].IsLeaf());
     }
 
     [Fact]
@@ -116,6 +118,8 @@ public class TreeTest
         Assert.Equal(a[0].Root(), list[1]);
         Assert.StartsWith("Root", a[0].Path());
         Assert.Equal(a[0].Level(), 20000);
+        Assert.True(tree[0].IsRoot());
+        Assert.True(list[1499].IsLeaf());
     }
 
     [Fact]