using System;
using System.Linq;
using System.Collections.Generic;
public static class MyExtensions
{
public static IEnumerable<T> Traverse<T>(
this IEnumerable<T> source,
Func<T, IEnumerable<T>> fnRecurse)
{
if (source != null)
{
Stack<IEnumerator<T>> enumerators = new Stack<IEnumerator<T>>();
try
{
enumerators.Push(source.GetEnumerator());
while (enumerators.Count > 0)
{
var top = enumerators.Peek();
while (top.MoveNext())
{
yield return top.Current;
var children = fnRecurse(top.Current);
if (children != null)
{
top = children.GetEnumerator();
enumerators.Push(top);
}
}
enumerators.Pop().Dispose();
}
}
finally
{
while (enumerators.Count > 0)
enumerators.Pop().Dispose();
}
}
}
}
public class Node
{
public int Id;
public List<Node> Children;
}
public class Test
{
public static void Main()
{
List<Node> nodes = new List<Node>()
{
new Node()
{
Id = 1,
Children = new List<Node>()
{
new Node()
{
Id = 2,
Children = new List<Node>()
{
new Node()
{
Id = 4
},
new Node()
{
Id = 5
}
}
},
new Node()
{
Id = 3
}
}
}
};
Console.WriteLine(String.Join(", ", nodes.Traverse(n => n.Children).Select(n => n.Id)));
}
}
ICAgIHVzaW5nIFN5c3RlbTsKICAgIHVzaW5nIFN5c3RlbS5MaW5xOwogICAgdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7CiAgICAgCiAgICBwdWJsaWMgc3RhdGljIGNsYXNzIE15RXh0ZW5zaW9ucwogICAgewogICAgCXB1YmxpYyBzdGF0aWMgSUVudW1lcmFibGU8VD4gVHJhdmVyc2U8VD4oCiAgICAJICAgIHRoaXMgSUVudW1lcmFibGU8VD4gc291cmNlLAogICAgCSAgICBGdW5jPFQsIElFbnVtZXJhYmxlPFQ+PiBmblJlY3Vyc2UpCiAgICAJewogICAgCQlpZiAoc291cmNlICE9IG51bGwpCiAgICAJCXsKICAgIAkJCVN0YWNrPElFbnVtZXJhdG9yPFQ+PiBlbnVtZXJhdG9ycyA9IG5ldyBTdGFjazxJRW51bWVyYXRvcjxUPj4oKTsKICAgIAkJCXRyeQogICAgCQkJewogICAgCQkJCWVudW1lcmF0b3JzLlB1c2goc291cmNlLkdldEVudW1lcmF0b3IoKSk7CiAgICAJCQkJd2hpbGUgKGVudW1lcmF0b3JzLkNvdW50ID4gMCkKICAgIAkJCQl7CiAgICAJCQkJCXZhciB0b3AgPSBlbnVtZXJhdG9ycy5QZWVrKCk7CiAgICAJCQkJCXdoaWxlICh0b3AuTW92ZU5leHQoKSkKICAgIAkJCQkJewogICAgCQkJCQkJeWllbGQgcmV0dXJuIHRvcC5DdXJyZW50OwogICAgIAogICAgCQkJCQkJdmFyIGNoaWxkcmVuID0gZm5SZWN1cnNlKHRvcC5DdXJyZW50KTsKICAgIAkJCQkJCWlmIChjaGlsZHJlbiAhPSBudWxsKQogICAgCQkJCQkJewogICAgCQkJCQkJCXRvcCA9IGNoaWxkcmVuLkdldEVudW1lcmF0b3IoKTsKICAgIAkJCQkJCQllbnVtZXJhdG9ycy5QdXNoKHRvcCk7CiAgICAJCQkJCQl9CiAgICAJCQkJCX0KICAgICAKICAgIAkJCQkJZW51bWVyYXRvcnMuUG9wKCkuRGlzcG9zZSgpOwogICAgCQkJCX0KICAgIAkJCX0KICAgIAkJCWZpbmFsbHkKICAgIAkJCXsKICAgIAkJCQl3aGlsZSAoZW51bWVyYXRvcnMuQ291bnQgPiAwKQogICAgCQkJCQllbnVtZXJhdG9ycy5Qb3AoKS5EaXNwb3NlKCk7CiAgICAJCQl9CiAgICAJCX0KICAgIAl9CiAgICB9CiAgICAgCiAgICBwdWJsaWMgY2xhc3MgTm9kZQogICAgewogICAgCXB1YmxpYyBpbnQgSWQ7CiAgICAJcHVibGljIExpc3Q8Tm9kZT4gQ2hpbGRyZW47CiAgICB9CiAgICAgCiAgICBwdWJsaWMgY2xhc3MgVGVzdAogICAgewogICAgCXB1YmxpYyBzdGF0aWMgdm9pZCBNYWluKCkKICAgIAl7CiAgICAJCUxpc3Q8Tm9kZT4gbm9kZXMgPSBuZXcgTGlzdDxOb2RlPigpCiAgICAJCXsKICAgIAkJCW5ldyBOb2RlKCkKICAgIAkJCXsKICAgIAkJCQlJZCA9IDEsCiAgICAJCQkJQ2hpbGRyZW4gPSBuZXcgTGlzdDxOb2RlPigpCiAgICAJCQkJewogICAgCQkJCQluZXcgTm9kZSgpCiAgICAJCQkJCXsKICAgIAkJCQkJCUlkID0gMiwKICAgIAkJCQkJCUNoaWxkcmVuID0gbmV3IExpc3Q8Tm9kZT4oKQogICAgCQkJCQkJewogICAgCQkJCQkJCW5ldyBOb2RlKCkKICAgIAkJCQkJCQl7CiAgICAJCQkJCQkJCUlkID0gNAogICAgCQkJCQkJCX0sCiAgICAJCQkJCQkJbmV3IE5vZGUoKQogICAgCQkJCQkJCXsKICAgIAkJCQkJCQkJSWQgPSA1CiAgICAJCQkJCQkJfQogICAgCQkJCQkJfQogICAgCQkJCQl9LAogICAgCQkJCQluZXcgTm9kZSgpCiAgICAJCQkJCXsKICAgIAkJCQkJCUlkID0gMwogICAgCQkJCQl9CiAgICAJCQkJfQogICAgCQkJfQogICAgCQl9OwogICAgIAogICAgCQlDb25zb2xlLldyaXRlTGluZShTdHJpbmcuSm9pbigiLCAiLCBub2Rlcy5UcmF2ZXJzZShuID0+IG4uQ2hpbGRyZW4pLlNlbGVjdChuID0+IG4uSWQpKSk7CiAgICAJfQogICAgfQ==