// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! namespace Admin.NET.Core; /// /// 树扩展方法 /// public static class TreeExtensions { /// /// 转为树形结构 /// /// 树节点数据类型 /// 源数据集合 /// 判断父子关系的函数,第一个参数为父级,第二个参数为子级 /// 转换后的树形结构根节点集合 public static IEnumerable> ToTree(this IEnumerable source, Func isChild) { var nodes = source.Select(value => new TreeNode(value)).ToList(); var visited = new HashSet(); foreach (var node in nodes) { if (visited.Contains(node.Value)) { continue; } var stack = new Stack>(); stack.Push(node); while (stack.Count > 0) { var current = stack.Pop(); if (visited.Contains(current.Value)) { throw new InvalidOperationException("转为树形结构时,循环依赖检测到"); } _ = visited.Add(current.Value); foreach (var child in nodes.Where(child => isChild(current.Value, child.Value))) { current.Children.Add(child); stack.Push(child); } } } return nodes.Where(node => !nodes.Any(n => n.Children.Contains(node))); } /// /// 根据主键和父级主键生成树形结构 /// /// 树节点数据类型 /// 源数据集合 /// 主键选择器 /// 父级主键选择器 /// 树形结构 public static IEnumerable> ToTree(this IEnumerable source, Func keySelector, Func parentKeySelector) { var nodes = source.Select(value => new TreeNode(value)).ToList(); var lookup = nodes.ToLookup(node => parentKeySelector(node.Value), node => node); foreach (var node in nodes) { node.Children.AddRange(lookup[keySelector(node.Value)]); } return nodes.Where(node => !nodes.Any(n => keySelector(n.Value).Equals(parentKeySelector(node.Value)))); } /// /// 添加子节点 /// /// 树节点数据类型 /// 父节点 /// 要添加的子节点值 /// public static void AddChild(this TreeNode parent, T value) { ArgumentNullException.ThrowIfNull(parent); parent.Children.Add(new TreeNode(value)); } /// /// 添加子节点到指定的父节点 /// /// 树节点数据类型 /// 源数据集合 /// 父节点对象 /// 子节点对象 /// 主键选择器 /// 父级主键选择器 public static void AddChild(this IEnumerable> source, T parent, T child, Func keySelector, Func parentKeySelector) { if (parent is null) { throw new ArgumentNullException(nameof(parent), "父节点不能为空"); } if (child is null) { throw new ArgumentNullException(nameof(child), "子节点不能为空"); } var parentNode = source .DepthFirstTraversal() .FirstOrDefault(node => keySelector(node.Value).Equals(keySelector(parent))) ?? throw new InvalidOperationException("在树中未找到父节点"); _ = parentKeySelector.Invoke(child).SetPropertyValue("Children", keySelector(parent)); parentNode.Children.Add(new TreeNode(child)); } /// /// 删除节点 /// /// 树节点数据类型 /// 根节点 /// 要删除的节点值 /// 如果成功删除节点则返回 true,否则返回 false public static bool RemoveNode(this TreeNode? root, T value) { if (root is null) { return false; } foreach (var child in root.Children.ToList()) { if (EqualityComparer.Default.Equals(child.Value, value)) { _ = root.Children.Remove(child); return true; } if (RemoveNode(child, value)) { return true; } } return false; } /// /// 深度优先遍历 (DFS) /// /// 树节点数据类型 /// 根节点 /// 深度优先遍历的节点序列 public static IEnumerable> DepthFirstTraversal(this TreeNode? root) { if (root is null) { yield break; } yield return root; foreach (var child in root.Children) { foreach (var descendant in child.DepthFirstTraversal()) { yield return descendant; } } } /// /// 深度优先遍历 (DFS) - 遍历树形结构中所有节点 /// /// 树节点数据类型 /// 树形结构根节点集合 /// 深度优先遍历的节点序列 public static IEnumerable> DepthFirstTraversal(this IEnumerable>? source) { if (source is null) { yield break; } foreach (var root in source) { foreach (var node in root.DepthFirstTraversal()) { yield return node; } } } /// /// 广度优先遍历 (BFS) /// /// 树节点数据类型 /// 根节点 /// 广度优先遍历的节点序列 public static IEnumerable> BreadthFirstTraversal(this TreeNode? root) { if (root is null) { yield break; } var queue = new Queue>(); queue.Enqueue(root); while (queue.Count > 0) { var current = queue.Dequeue(); yield return current; foreach (var child in current.Children) { queue.Enqueue(child); } } } /// /// 查找节点 (DFS) /// /// 树节点数据类型 /// 根节点 /// 要查找的节点值 /// 找到的节点,如果未找到则返回 null public static TreeNode? FindNode(this TreeNode root, T value) { return root.DepthFirstTraversal().FirstOrDefault(node => EqualityComparer.Default.Equals(node.Value, value)); } /// /// 获取节点路径 /// /// 树节点数据类型 /// 根节点 /// 要获取路径的节点值 /// 从根节点到目标节点的路径,如果未找到则返回 null public static List>? GetPath(this TreeNode root, T value) { var path = new List>(); return FindPath(root, value, path) ? path : null; } /// /// 获取树的高度 /// /// 树节点数据类型 /// 根节点 /// 树的高度,空树返回 0 public static int GetHeight(this TreeNode? root) { return root is null ? 0 : 1 + root.Children.Select(child => child.GetHeight()).DefaultIfEmpty(0).Max(); } /// /// 获取叶子节点 /// /// 树节点数据类型 /// 根节点 /// 所有叶子节点的集合 public static IEnumerable> GetLeafNodes(this TreeNode root) { return root.DepthFirstTraversal().Where(node => node.Children.Count == 0); } #region 私有方法 /// /// 查找路径 /// /// 树节点数据类型 /// 当前节点 /// 要查找的节点值 /// 路径记录 /// 如果找到目标节点则返回 true,否则返回 false private static bool FindPath(TreeNode? node, T value, List> path) { if (node is null) { return false; } path.Add(node); if (EqualityComparer.Default.Equals(node.Value, value)) { return true; } foreach (var child in node.Children) { if (FindPath(child, value, path)) { return true; } } path.RemoveAt(path.Count - 1); return false; } #endregion 私有方法 /// /// 设置对象属性值 /// /// /// /// /// /// /// public static bool SetPropertyValue(this TEntity entity, string propertyName, TValue value) { var objectType = typeof(TEntity); var propertyInfo = objectType.GetProperty(propertyName); if (propertyInfo is null || !propertyInfo.PropertyType.IsGenericType) { throw new ArgumentException($"属性 '{propertyName}' 不存在,或者不是类型 '{objectType.Name}' 中的泛型类型。"); } var paramObj = Expression.Parameter(objectType); var paramVal = Expression.Parameter(typeof(TValue)); var bodyVal = Expression.Convert(paramVal, propertyInfo.PropertyType); // 获取设置属性的值的方法 var setMethod = propertyInfo.GetSetMethod(true); // 如果只是只读,则 setMethod==null if (setMethod is null) { return false; } var body = Expression.Call(paramObj, setMethod, bodyVal); var setValue = Expression.Lambda>(body, paramObj, paramVal).Compile(); setValue(entity, value); return true; } } /// /// 树节点数据传输对象 /// /// public class TreeNode { /// /// 构造函数 /// /// 节点值 public TreeNode(T value) { Value = value; } /// /// 节点值 /// public T Value { get; set; } /// /// 子节点 /// public List> Children { get; set; } = []; }