In my previous article "C # Extension Method whimsical use advanced Article 6: winform control selector", a winform selector is provided. Its essence is a "Tree" traversal tool, however, this traversal is limited to the control class of winform. In the data structure, "Tree" traversal is a general algorithm. Why do we not make a general "Tree" traversal extension?
Let's first look at a simple class people (which will be used as an example for testing ):
1 public abstract class people
2 {
3 Public bool ismale {Get; private set ;}
4 public abstract ienumerable <people> children {Get ;}
5}
The people class has a children attribute that returns all children of the people. The people class uses the children attribute to form a People Tree.
The general traversal extension of the "Tree" is as follows:
1 public static ienumerable <t> getdescendants <t> (this t root,
2 func <t, ienumerable <t> childselector, predicate <t> filter)
3 {
4 foreach (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}
Write several call examples using the people class:
1 people;
2 //
3 // obtain all descendants
4 var descendants = people. getdescendants (P => P. Children, null );
5 // obtain all male children
6 var males = people. getdescendants (P => P. Children, P => P. ismale );
Of course, there is another situation where only the children of this tribe can be obtained (Women in the children's family are married, not their children). This situation is a little complicated. This article focuses more on ideas, the sample code is no longer provided (which can be implemented by a friend and sent to the reply ).
Since it is common, let's use it in winform as a selector:
1 // form1.cs
2 // obtain all controls of this form
3 var controls = (this as control). getdescendants (C => C. Controls. Cast <control> (), null );
4 // obtain all the selected checkboxes
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> ();
General Methods certainly do not have dedicated elegance in writing, and multiple is/As and cast are used, mainly because inheritance is involved here, and the type controlcollection of the Control. CONTROLS attribute is not a generic set.
The preceding two examples are similar: the "root" in the tree structure is of the same type (or has the same base class) as the "child", and the Treeview in winform is different: Treeview (Root) contains multiple treenode (child). Each treenode can also contain multiple treenode (child). The "root" and "child" types are different (and there is no same base class), such:
We need to use another extension (to call the above Extension Method ):
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 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}
The call code is as follows:
1 // obtain all Tree nodes ending with "Wine" in the Treeview
2 var treeviewnode = treeview1.getdescendants (
3 Treeview => Treeview. nodes. Cast <treenode> (),
4 treenode => treenode. nodes. Cast <treenode> (),
5 treenode => treenode. Text. endswith ("Wine ")
6 );
With these two extensions, I believe they can meet the requirements of most "Tree" traversal. For convenience, we can also perform some heavy loads.
In addition, the traversal of the "Tree" takes precedence over depth and breadth. Here, we will not give examples one by one.
Please stay tuned to my series of articles "C # great use of extension methods!