static class Dumper { static public string Dump(Node root) { /* ... */ Worker dumper = new Worker(); dumper.Dump(root, ""); return dumper.ToString(); } /// /// Does the actual work; I like Dumper being a static class since all public methods in it are static /// private class Worker { private const string VerticalIndent = "│ "; private const string EmptyVerticalIndent = " "; private const string ChildIndent = "├─"; private const string LastChildIndent = "└─"; private StringBuilder output = new StringBuilder(); private List indentStack = new List(); /// /// Dumps the given node. The beforeRoot is printed before the root node's text. /// public void Dump(Node node, string beforeRoot) { Indent(); output.Append(beforeRoot); output.AppendLine(node.Text); if (node.Children.Count > 0) DumpChildren(node); } /// /// Dumps the children of the node. Assumes that there are children, i.e. node.Children.Count > 0 /// private void DumpChildren(Node node) { indentStack.Push(VerticalIndent); for (int i = 0; i < node.Children.Count - 1; i++) { Dump(node.Children[i], ChildIndent); } indentStack.Pop(); indentStack.Push(EmptyVerticalIndent); Dump(node.Children[node.Children.Count - 1], LastChildIndent); indentStack.Pop(); } /// /// Indents properly. Prints the indentStack, except the last item. /// private void Indent() { for (int i = 0; i < indentStack.Count - 1; i++) { output.Append(indentStack[i]); } } /// /// Returns the string representation of the dump /// /// public override string ToString() { return output.ToString(); } } } /// /// Allows us to treat a list as a stack, ordered from the first to last item. /// Provides Push to add a last item and Pop to remove it. /// static class ListStackExtensions { public static void Push(this List list, T item) { list.Add(item); } // I didn't bother returning the removed item because I don't need it in this case public static void Pop(this List list) { list.RemoveAt(list.Count - 1); } }