using System.Collections.Generic;
using System.Diagnostics;
public static class LinqExtension
public static IEnumerable<T> Traverse<T>(this T item, Func<T,T> childSelector)
var stack = new Stack<T>(new T[]{item});
stack.Push(childSelector(next));
public static IEnumerable<T> Traverse<T>(this T item, Func<T,IEnumerable<T>> childSelector)
var stack = new Stack<T>(new T[]{item});
foreach (var child in childSelector(next))
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> items,
Func<T, IEnumerable<T>> childSelector)
var stack = new Stack<T>(items);
foreach(var child in childSelector(next))
public static void Main()
UnitTest unitTest = new UnitTest();
unitTest.Assert(false, "Test Failure {0}", new object[]{-1});
unitTest.TestDescendantType();
unitTest.TestEnumerableSelector();
unitTest.TestEnumerable();
unitTest.TestReverseTraversal();
public void Assert(bool Assertion, string details = "", object[] args = null)
var caller = new StackFrame(1, true).GetMethod().Name;
Debug.Assert(Assertion, caller, details, args);
Console.WriteLine("Fail: {0} - {1}", caller, string.Format(details, args));
public void TestSameType()
var innerException = new Exception("Root Exception");
innerException.Data["Error Code"] = -1;
var exception = new Exception("oh no", innerException);
var allExceptions = exception.Traverse(ex => ex.InnerException);
Assert(allExceptions.Count () == 2);
var lookingForKey = "Error Code";
allExceptions.Where (e => e.Data != null
&& e.Data.Contains(lookingForKey)
&& e.Data[lookingForKey] is int
&& (int)e.Data[lookingForKey] == -1
public void TestDescendantType()
var innerException = new Exception("root error");
var exception = new ApplicationException("oh no", innerException);
var allExceptions = exception.Traverse<Exception>(ex => ex.InnerException);
Assert(allExceptions.Count () == 2);
public void TestEnumerableSelector()
var folder = new Folder(2, 2) {Name = "Root"};
var allFolders = folder.Traverse(f => f.SubFolders);
Assert(allFolders.Count () == 7, System.Reflection.MethodInfo.GetCurrentMethod().Name);
Assert(allFolders.Where (f => f != folder).Count () == 6,
Assert(folder.SubFolders.Traverse(f => f.SubFolders).Count () == 6,
"Exclude Parent Example 2");
public void TestEnumerable()
var folder = new Folder(2,2){Name = "Root"};
var allSubFolders = folder.SubFolders.Traverse(f => f.SubFolders);
Assert(allSubFolders.Count () == 6);
public void TestReverseTraversal()
var folder = new Folder(2,2){Name = "Root"};
var subFolder = folder.SubFolders.Last ().SubFolders.Last ();
var allParents = subFolder.Traverse(f => f.Parent);
Assert(allParents.Count () == 3);
private static string[] TestNames = {"Samson","Mohammad","Grant","Ross","Sean","Oscar","Edan","Ryder","Arden","Raphael",
"Dolan","Dillon","Burton","Hunter","Lewis","Rooney","Gareth","Vladimir","Uriah","Xavier",
"Plato","Lance","Baxter","Aristotle","Brian","Ralph","Dillon","Cullen","Joel","Matthew",
"Thomas","Kenyon","Gregory","Francis","Odysseus","Samuel","Peter","Conan","Jarrod",
"Ezekiel","Tarik","Odysseus","Adam","Fulton","Callum","Gage","Gannon","Silas","Allen",
"Avram","Kenneth","Dieter","Ishmael","Josiah","Sebastian","Acton","Elijah","Nehru",
"Upton","Ferdinand","Brendan","Edan","Carter","Erasmus","Zeph","Colin","Noble","Chase",
"Colin","Gray","Micah","Amos","Kasimir","Armand","Upton","Dane","Carter","Zephania","Aladdin",
"Keith","Malcolm","Marshall","Norman","Jerry","Bevis","Connor","Fulton","Colby","Eaton",
"Ivan","Zane","Abel","Ryder","Benedict","Austin","Garrett","Dexter","Cain","Yuli","Theodore",};
private static IEnumerable<string> AvailableNames = new List<string>();
public Folder(int subFolderCount, int levels)
if(AvailableNames.Count () == 0)
AvailableNames = new List<String>(TestNames);
SubFolders = new List<Folder>(subFolderCount);
for(int i = 0; i < subFolderCount; i++)
SubFolders.Add(new Folder(subFolderCount, levels -1)
Name = AvailableNames.First (),
AvailableNames = new List<string>(AvailableNames.Skip(1));
public string Name{get;set;}
public IList<Folder> SubFolders{get;set;}
public Folder Parent{get;set;}