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

先看一个简单的类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);

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

既然是通用的,我们就将它用在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(子孙),“根”与“子孙”类型不同(也没有相同的基类),如下图:


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

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 );

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

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

时间: 2024-12-03 20:22:18

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

c#扩展方法奇思妙用高级篇八:Type类扩展

Type 类提供了大量的属性和方法,但在一些基础性开发工作中,Type类功能还有些欠缺,尤其上在处理泛型类型时,如可空类型和泛型集合类型.下面的类就针对这些地方进行扩展. 1 public static class TypeHelper 2 { 3 public static bool IsNullableType(this Type type) 4 { 5 return (((type != null) && type.IsGenericType) && 6 (type.

c#扩展方法奇思妙用高级篇五:ToString(string format) 扩展

在.Net中,System.Object.ToString()是用得最多的方法之一,ToString()方法在Object类中被定义为virtual,Object类给了它一个默认实现: 1 public virtual string ToString() 2 { 3 return this.GetType().ToString(); 4 } .Net中原生的class或struct,如int,DateTime等都对它进行重写(override),以让它返回更有价值的值,而不是类型的名称.合理重写

c#扩展方法奇思妙用高级篇四:对扩展进行分组管理

从系列文章开篇到现在,已经实现的很多扩展了,但过多的扩展会给我们带来很多麻烦,试看下图: 面对这么多"泛滥"的扩展,很多人都会感到很别扭,的确有种"喧宾夺主"的感觉,想从中找出真正想用的方法来太难了!尽管经过扩展后的string类很"强大",但易用性确很差. 很多人因此感觉扩展应适可而止,不该再继续下去...其实这是一种逃避问题的态度,出现问题我们应该主动去解决,而不是去回避! 有很多种方法可以解决以上问题,最简单的就是使用将扩展放入不同name

c#扩展方法奇思妙用高级篇二:Aggregate扩展其改进

Enumerable.Aggregate 扩展方法在System.Linq命名空间中,是Enumerable类的第一个方法(按字母顺序排名),但确是Enumerable里面相对复杂的方法. MSDN对它的说明是:对序列应用累加器函数.备注中还有一些说明,大意是这个方法比较复杂,一般情况下用Sum.Max.Min.Average就可以了. 看看下面的代码,有了Sum,谁还会用Aggregate呢! public static void Test1() { int[] nums = new int[

c#扩展方法奇思妙用高级篇一:改进Scottgu的"In"扩展

先看下ScottGu对In的扩展: 调用示例1: 调用示例2: 原文地址:New "Orcas" Language Feature: Extension Methods(http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx) 很多介绍扩展方法的也大都使用"In"作为例子,但很少有人再深入想一步.个人感觉这个In扩展的不够彻

c#扩展方法奇思妙用高级篇三:Enumerable.Cast&amp;lt;T&amp;gt;应用

Enumerable.Cast<T>用于将IEnumerable转换为泛型版本IEnumerable<T>.转换后可尽情享用Enumerable的其它方法(如Where.Select),给我们的编码带来极大便利. 但MSDN中仅给出一个转换ArrayList的例子,很多人看了感觉现在都在用List<T>,还有谁会用ArrayList,Cast<T>没多少用处,除非处理一些之前遗留的一些代码. 其实Cast<T>并非如此简单,它可以用在很多地方.

c#扩展方法奇思妙用高级篇六:WinForm控件选择器

我们先看几个类图,深入认识一下我们常用的WinForm控件: 图1 ScrollableControl类图 图2 ButtonBase类图 图3 TextBoxBase类图 图4 ListControl类图 图5 Label类图 图6 其它常用 从图1中可以看出,Form与Button.Label一样,也是一个Control.

艾伟_转载:c#扩展方法奇思妙用变态篇四:string 的翻身革命

   string是各种编程语言中最基础的数据类型,长期以来受尽其它类的压迫,经常被肢解(Substring.Split).蹂躏(Join)...  而现在string要"翻身闹革命"了,它几乎无所不能,可以为所欲为,令其它类心惊胆颤...    让我们来看一下革命后的string做了些什么?  1. 打开文件或网址 1      "c:\\t.txt".Open();2      "http://www.cnblogs.com/ldp615/"

c#扩展方法奇思妙用变态篇四:string 的翻身革命

string是各种编程语言中最基础的数据类型,长期以来受尽其它类的压迫,经常被肢解(Substring.Split).蹂躏(Join)... 而现在string要"翻身闹革命"了,它几乎无所不能,可以为所欲为,令其它类心惊胆颤... 让我们来看一下革命后的string做了些什么? 1. 打开文件或网址 1      "c:\\t.txt".Open(); 2      "http://www.cnblogs.com/ldp615/".Open()