c#扩展方法奇思妙用高级篇七:“树”通用遍历器
我的上一篇隨筆《c#擴展方法奇思妙用高級篇六:WinForm 控件選擇器》中給出了一個WinForm的選擇器,其實質就是一個“樹”的遍歷器,但這個遍歷局限于WinForm的Control類。在數據結構中,“樹”的遍歷是一個通用算法,那我們為什么不做一個通用的“樹”遍歷擴展呢?
?
?先看一個簡單的類People(將作為測試用的例子):
1?????public?abstract?class?People2?????{
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.cs2?????//獲取本窗體所有控件
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?????????);
?
?有了這兩個擴展,相信能滿足大部分“樹”的遍歷,為了使用方便還可以進行一些重載。
?另外,“樹”的遍歷有 深度優先 和 廣度優先,這里只提一下,就不再一一給出示例了。
轉載于:https://www.cnblogs.com/ywsoftware/archive/2013/06/09/3128778.html
總結
以上是生活随笔為你收集整理的c#扩展方法奇思妙用高级篇七:“树”通用遍历器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js关于事件冒泡
- 下一篇: 工作之本地存储RAID5一硬盘离线恢复简