VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > C#教程 >
  • c#之“树”通用遍历器

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  先看一个简单的类People(将作为测试用的例子):

1     public abstract class People
2     {
3         public bool IsMale { get; private set; }
4         public abstract IEnumerable<People> Children { get; }
5     }

  People类有一个Children属性,返回该People的所有孩子。People类通过Children属性最终可形成一个People树。

  “树”的通用遍历扩展参照如下:

 1     public static IEnumerable<T> GetDescendants<T>(this T root, 
 2         Func<T, IEnumerable<T>> childSelector, Predicate<T> filter)
 3     {
 4         foreach (T t in childSelector(root))
 5         {
 6             if (filter == null || filter(t))
 7                 yield return t;
 8             foreach (T child in GetDescendants((T)t, childSelector, filter))
 9                 yield return child;
10         }
11     }

  使用People类,写出几个调用示例:

1     People people;
2     //
3     //获取所有子孙
4      var descendants = people.GetDescendants(p => p.Children, null);
5     //获取所有男性子孙
6     var males = people.GetDescendants(p => p.Children, p => p.IsMale);

编缉推荐阅读以下文章

  • c#扩展方法奇思妙用高级篇六:WinForm 控件选择器
  • c#扩展方法奇思妙用高级篇五:ToString(string format) 扩展
  • c#扩展方法奇思妙用高级篇四:对扩展进行分组管理
  • c#扩展方法奇思妙用性能篇一:扩展方法性能初测
  • c#扩展方法奇思妙用基础篇三:byte 常用扩展
  • c#扩展方法奇思妙用基础篇二:string 常用扩展
  • c#扩展方法奇思妙用基础篇一:中文处理
  • c#扩展方法奇思妙用高级篇三:Enumerable.Cast应用
  • c#扩展方法奇思妙用高级篇二:Aggregate扩展其改进
  • c#扩展方法奇思妙用高级篇一:改进 Scottgu 的 "In" 扩展
 

  当然,还有另外一种情况,只获取本族人的子孙(子孙中的女性嫁出,不包括她们的子孙),这种情况稍复杂些,本文更侧重想法,不再给出示例代码(哪们朋友实现了,可发在回复中)。

  既然是通用的,我们就将它用在WinForm中作为选择器试试吧:

1     //Form1.cs
2     //获取本窗体所有控件
3     var controls = (this as Control).GetDescendants(c => c.Controls.Cast<Control>(), null);
4     //获取所有选中的CheckBox
5     var checkBoxes = (this as Control).GetDescendants(
6             c => c.Controls.Cast<Control>(),
7             c => (c is CheckBox) && (c as CheckBox).Checked
8         )
9         .Cast<CheckBox>();

  通用的方法写起来肯定没有专用的优雅,用了多处 is/as 和 Cast,主要因为这里涉及到继承,而且Control.Controls属性的类型ControlCollection不是泛型集合。

  以上两个例子比较相似:树结构中“根”与“子孙”类型相同(或具有相同的基类),WinForm中的TreeView就不同了:TreeView(根)包含多个TreeNode(子孙),每个TreeNode也可包含多个TreeNode(子孙),“根”与“子孙”类型不同(也没有相同的基类),如下图:

c#扩展方法奇思妙用高级篇七:“树”通用遍历器 

编缉推荐阅读以下文章

  • c#扩展方法奇思妙用高级篇六:WinForm 控件选择器
  • c#扩展方法奇思妙用高级篇五:ToString(string format) 扩展
  • c#扩展方法奇思妙用高级篇四:对扩展进行分组管理
  • c#扩展方法奇思妙用性能篇一:扩展方法性能初测
  • c#扩展方法奇思妙用基础篇三:byte 常用扩展
  • c#扩展方法奇思妙用基础篇二:string 常用扩展
  • c#扩展方法奇思妙用基础篇一:中文处理
  • c#扩展方法奇思妙用高级篇三:Enumerable.Cast应用
  • c#扩展方法奇思妙用高级篇二:Aggregate扩展其改进
  • c#扩展方法奇思妙用高级篇一:改进 Scottgu 的 "In" 扩展
 

  我们要使用另外一个扩展(要调用上面的扩展方法):

 1     public static IEnumerable<T> GetDescendants<TRoot, T>(this TRoot root, 
 2         Func<TRoot, IEnumerable<T>> rootChildSelector,  
 3         Func<T, IEnumerable<T>> childSelector, Predicate<T> filter)
 4     {
 5         foreach (T t in rootChildSelector(root))
 6         {
 7             if (filter == null || filter(t))
 8                 yield return t;
 9             foreach (T child in GetDescendants(t, childSelector, filter))
10                 yield return child;
11         }
12     }

  调用代码如下:

1     //获取TreeView中所有以“酒”结尾的树结点             
2     var treeViewNode = treeView1.GetDescendants(
3         treeView => treeView.Nodes.Cast<TreeNode>(),
4         treeNode => treeNode.Nodes.Cast<TreeNode>(),
5         treeNode => treeNode.Text.EndsWith("酒")
6         );

  有了这两个扩展,相信能满足大部分“树”的遍历,为了使用方便还可以进行一些重载。

  另外,“树”的遍历有 深度优先 和 广度优先,这里只提一下,就不再一一给出示例了。

编缉推荐阅读以下文章

  • c#扩展方法奇思妙用高级篇六:WinForm 控件选择器
  • c#扩展方法奇思妙用高级篇五:ToString(string format) 扩展
  • c#扩展方法奇思妙用高级篇四:对扩展进行分组管理
  • c#扩展方法奇思妙用性能篇一:扩展方法性能初测
  • c#扩展方法奇思妙用基础篇三:byte 常用扩展
  • c#扩展方法奇思妙用基础篇二:string 常用扩展
  • c#扩展方法奇思妙用基础篇一:中文处理
  • c#扩展方法奇思妙用高级篇三:Enumerable.Cast应用
  • c#扩展方法奇思妙用高级篇二:Aggregate扩展其改进
  • c#扩展方法奇思妙用高级篇一:改进 Scottgu 的 "In" 扩展
 

  当然,还有另外一种情况,只获取本族人的子孙(子孙中的女性嫁出,不包括她们的子孙),这种情况稍复杂些,本文更侧重想法,不再给出示例代码(哪们朋友实现了,可发在回复中)。

  既然是通用的,我们就将它用在WinForm中作为选择器试试吧:

1     //Form1.cs
2     //获取本窗体所有控件
3     var controls = (this as Control).GetDescendants(c => c.Controls.Cast<Control>(), null);
4     //获取所有选中的CheckBox
5     var checkBoxes = (this as Control).GetDescendants(
6             c => c.Controls.Cast<Control>(),
7             c => (c is CheckBox) && (c as CheckBox).Checked
8         )
9         .Cast<CheckBox>();

  通用的方法写起来肯定没有专用的优雅,用了多处 is/as 和 Cast,主要因为这里涉及到继承,而且Control.Controls属性的类型ControlCollection不是泛型集合。

  以上两个例子比较相似:树结构中“根”与“子孙”类型相同(或具有相同的基类),WinForm中的TreeView就不同了:TreeView(根)包含多个TreeNode(子孙),每个TreeNode也可包含多个TreeNode(子孙),“根”与“子孙”类型不同(也没有相同的基类),如下图:

c#扩展方法奇思妙用高级篇七:“树”通用遍历器 

编缉推荐阅读以下文章

  • c#扩展方法奇思妙用高级篇六:WinForm 控件选择器
  • c#扩展方法奇思妙用高级篇五:ToString(string format) 扩展
  • c#扩展方法奇思妙用高级篇四:对扩展进行分组管理
  • c#扩展方法奇思妙用性能篇一:扩展方法性能初测
  • c#扩展方法奇思妙用基础篇三:byte 常用扩展
  • c#扩展方法奇思妙用基础篇二:string 常用扩展
  • c#扩展方法奇思妙用基础篇一:中文处理
  • c#扩展方法奇思妙用高级篇三:Enumerable.Cast应用
  • c#扩展方法奇思妙用高级篇二:Aggregate扩展其改进
  • c#扩展方法奇思妙用高级篇一:改进 Scottgu 的 "In" 扩展


相关教程