using System;
using System.Collections.Generic;
using System.Linq;
namespace Linq.Extensions
{
public static class LinqExtensions
{
public static IEnumerable<T> Recurse<T>
(
this T root,
Func<T, IEnumerable<T>> findChildren
)
where T : class
{
yield return root;
foreach (var child in
findChildren(root)
.SelectMany(node => Recurse(node, findChildren))
.TakeWhile(child => child != null))
{
yield return child;
}
// SAME CODE AS ABOVE IN A MORE VERBOSE FASHION
//foreach (var node in findChildren(root))
//{
// foreach (var child in Recurse(node, findChildren))
// {
// if (child == null)
// yield break;
// yield return child;
// }
//}
}
}
}
<Root>
<ChildA>
<SubChildA></SubChildA>
<SubChildB></SubChildB>
<SubChildC></SubChildC>
</ChildA>
<ChildB>
<SubChildA></SubChildA>
<SubChildB></SubChildB>
</ChildB>
<ChildC>
<SubChildA></SubChildA>
</ChildC>
<ChildD>
</ChildD>
</Root>
[TestMethod]
public void TestXmlRecursion()
{
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(Resources.SampleXmlData);
foreach (var node in xmlDocument.FirstChild.Recurse(EnumerateXmlElements))
{
WriteXmlNode(node);
}
}
private static void WriteXmlNode(XmlNode node)
{
Debug.WriteLine(node.Name);
}
public IEnumerable<XmlNode> EnumerateXmlElements(XmlNode node)
{
return node.ChildNodes.Cast<XmlNode>();
}
[TestMethod]
public void TestFileSystemRecursion()
{
const string rootPath = @"C:\inetpub\";
foreach (var path in rootPath.Recurse(EnumerateFileSystemEntries))
{
WritePath(path);
}
}
public IEnumerable<string> EnumerateFileSystemEntries(string root)
{
if (Directory.Exists(root))
{
foreach (var fileSystemEntry in Directory.EnumerateFileSystemEntries(root))
{
yield return fileSystemEntry;
}
}
yield return null;
}
public static void WritePath(string path)
{
Debug.WriteLine(path);
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace Linq.Extensions
{
public static class LinqExtensions
{
public static IEnumerable<T> Recurse<T>
(
this T root,
Func<T, IEnumerable<T>> findChildren
)
where T : class
{
yield return root;
foreach (var child in
findChildren(root)
.SelectMany(node => Recurse(node, findChildren))
.TakeWhile(child => child != null))
{
yield return child;
}
// SAME CODE AS ABOVE IN A MORE VERBOSE FASHION
//foreach (var node in findChildren(root))
//{
// foreach (var child in Recurse(node, findChildren))
// {
// if (child == null)
// yield break;
// yield return child;
// }
//}
}
}
}
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using Linq.Extensions.UnitTests.Properties;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Linq.Extensions.UnitTests
{
[TestClass]
public class RecurseUnitTest
{
[TestMethod]
public void TestFileSystemRecursion()
{
const string rootPath = @"C:\inetpub\";
foreach (var path in rootPath.Recurse(EnumerateFileSystemEntries))
{
WritePath(path);
}
}
[TestMethod]
public void TestFileSystemRecursionImprovedPerformance()
{
FileSystemInfo info = new DirectoryInfo(@"C:\inetpub\");
foreach (var path in info.Recurse(EnumerateFileSystemEntriesImprovedPerformance))
{
WritePath(path);
}
}
[TestMethod]
public void TestXmlRecursion()
{
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(Resources.SampleXmlData);
foreach (var node in xmlDocument.FirstChild.Recurse(EnumerateXmlElements))
{
WriteXmlNode(node);
}
}
[TestMethod]
public void TestXmlRecursionReverse()
{
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(Resources.SampleXmlData);
foreach (var node in xmlDocument.FirstChild.Recurse(EnumerateXmlElements).Reverse())
{
WriteXmlNode(node);
}
}
[TestMethod]
public void TestWindowsFormsTreeRecursion()
{
var form = new FormTreeView();
foreach (var node in form.treeView.Nodes[0].Recurse(EnumerateTreeViewNodes))
{
WriteTreeViewNode(node);
}
}
private static void WriteTreeViewNode(TreeNode node)
{
Debug.WriteLine(node.Text);
}
private static void WriteXmlNode(XmlNode node)
{
Debug.WriteLine(node.Name);
}
public IEnumerable<TreeNode> EnumerateTreeViewNodes(TreeNode node)
{
return node.Nodes.Cast<TreeNode>();
}
public IEnumerable<XmlNode> EnumerateXmlElements(XmlNode node)
{
return node.ChildNodes.Cast<XmlNode>();
}
public IEnumerable<string> EnumerateFileSystemEntries(string root)
{
if (Directory.Exists(root))
{
foreach (var fileSystemEntry in Directory.EnumerateFileSystemEntries(root))
{
yield return fileSystemEntry;
}
}
}
public IEnumerable<FileSystemInfo> EnumerateFileSystemEntriesImprovedPerformance(FileSystemInfo info)
{
var rootDirectoryInfo = info as DirectoryInfo;
if (rootDirectoryInfo == null) yield break;
foreach (var directoryInfo in rootDirectoryInfo.GetDirectories())
{
yield return directoryInfo;
}
foreach (var fileInfo in rootDirectoryInfo.GetFiles())
{
yield return fileInfo;
}
}
public static void WritePath(string path)
{
Debug.WriteLine(path);
}
public static void WritePath(FileSystemInfo info)
{
Debug.WriteLine(info.FullName);
}
}
}
<Root>
<ChildA>
<SubChildA></SubChildA>
<SubChildB></SubChildB>
<SubChildC></SubChildC>
</ChildA>
<ChildB>
<SubChildA></SubChildA>
<SubChildB></SubChildB>
</ChildB>
<ChildC>
<SubChildA></SubChildA>
</ChildC>
<ChildD>
</ChildD>
</Root>
namespace Linq.Extensions.UnitTests
{
partial class FormTreeView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("SubChildA");
System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("SubChildB");
System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("SubChildC");
System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("ChildA", new System.Windows.Forms.TreeNode[] {
treeNode1,
treeNode2,
treeNode3});
System.Windows.Forms.TreeNode treeNode5 = new System.Windows.Forms.TreeNode("SubChildA");
System.Windows.Forms.TreeNode treeNode6 = new System.Windows.Forms.TreeNode("SubChildB");
System.Windows.Forms.TreeNode treeNode7 = new System.Windows.Forms.TreeNode("ChildB", new System.Windows.Forms.TreeNode[] {
treeNode5,
treeNode6});
System.Windows.Forms.TreeNode treeNode8 = new System.Windows.Forms.TreeNode("SubChildA");
System.Windows.Forms.TreeNode treeNode9 = new System.Windows.Forms.TreeNode("ChildC", new System.Windows.Forms.TreeNode[] {
treeNode8});
System.Windows.Forms.TreeNode treeNode10 = new System.Windows.Forms.TreeNode("ChildD");
System.Windows.Forms.TreeNode treeNode11 = new System.Windows.Forms.TreeNode("RootA", new System.Windows.Forms.TreeNode[] {
treeNode4,
treeNode7,
treeNode9,
treeNode10});
System.Windows.Forms.TreeNode treeNode12 = new System.Windows.Forms.TreeNode("RootB");
this.treeView = new System.Windows.Forms.TreeView();
this.SuspendLayout();
//
// treeView
//
this.treeView.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeView.Location = new System.Drawing.Point(0, 0);
this.treeView.Name = "treeView";
treeNode1.Name = "Node7";
treeNode1.Text = "SubChildA";
treeNode2.Name = "Node8";
treeNode2.Text = "SubChildB";
treeNode3.Name = "Node9";
treeNode3.Text = "SubChildC";
treeNode4.Name = "Node3";
treeNode4.Text = "ChildA";
treeNode5.Name = "Node10";
treeNode5.Text = "SubChildA";
treeNode6.Name = "Node11";
treeNode6.Text = "SubChildB";
treeNode7.Name = "Node4";
treeNode7.Text = "ChildB";
treeNode8.Name = "Node12";
treeNode8.Text = "SubChildA";
treeNode9.Name = "Node5";
treeNode9.Text = "ChildC";
treeNode10.Name = "Node6";
treeNode10.Text = "ChildD";
treeNode11.Name = "Node0";
treeNode11.Text = "RootA";
treeNode12.Name = "Node2";
treeNode12.Text = "RootB";
this.treeView.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
treeNode11,
treeNode12});
this.treeView.Size = new System.Drawing.Size(284, 262);
this.treeView.TabIndex = 0;
//
// FormTreeView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.treeView);
this.Name = "FormTreeView";
this.Text = "FormTreeView";
this.ResumeLayout(false);
}
#endregion
public System.Windows.Forms.TreeView treeView;
}
}
LinqRecurseExtension.zip
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (0)