在树结构上实现IEnumerable
根据这些家伙的工作:
- http://dvanderboom.wordpress.com/2008/03/15/treet-implementing-a-non-binary-tree-in-c/
- http://www.matthidinger.com/archive/2009/02/08/asp.net-mvc-recursive-treeview-helper.aspx
我正在尝试实现一个可以这样使用的TreeView助手:
r.Children, r => r.ID) %>
树结构的定义如下:
public class Tree : TreeNode where T : TreeNode { } public class TreeNode : IDisposable where T : TreeNode { public T Parent { get; set; } public TreeNodeList Children { get; set; } } public class TreeNodeList : List<TreeNode> where T : TreeNode { public T Parent; public T Add(T node) { base.Add(node); node.Parent = (T)Parent; return node; } public void Remove(T node) { if (node != null) node.Parent = null; base.Remove(node); } }
TreeView助手有这个签名:
public static string TreeView(this HtmlHelper htmlHelper, string treeId, IEnumerable rootItems, Func<T, IEnumerable> childrenProperty, Func itemContent, bool includeJavascript, string emptyContent) { ... }
因此,我需要我的Tree struture来实现IEnumerable,所以我可以将它与TreeView帮助器一起使用,这导致了一个问题:在这种情况下我将在何处以及如何实现IEnumerable?
对于想要实现递归树迭代器的人来说,Wes Dyer的这篇文章很好读:
http://blogs.msdn.com/wesdyer/archive/2007/03/23/all-about-iterators.aspx
我不完全理解树结构的确切细节,但这是一个简单的实现,它采用通用的节点树并递归地将其呈现为html列表。
public static string TreeView(IEnumerable rootItems, Func> childrenProperty, Func itemContent) { if (rootItems == null || !rootItems.Any()) return null; var builder = new StringBuilder(); builder.AppendLine(""); foreach (var item in rootItems) { builder.Append(" - ").Append(itemContent(item)).AppendLine("
"); var childContent = htmlHelper.TreeView(treeId, childrenProperty(item), childrenProperty, itemContent); if (childContent != null) { var indented = childContent.Replace(Environment.NewLine, Environment.NewLine + " "); builder.Append(" ").AppendLine(indented); } } builder.Append("
"); return builder.ToString(); }
我正在使用的节点类相对简单,只有两个属性。
public class Node { public Node(T data) { Data = data; Children = new List>(); } public T Data { get; private set; } public ICollection> Children { get; private set; } }
这是一些将树输出到控制台的测试代码。
var Records = new[] { new Node("one") { Children = { new Node ("one-one") { Children = { new Node ("one-one-one"), new Node ("one-one-two"), new Node ("one-one-three") } }, new Node ("one-two"), new Node ("one-three") } }, new Node ("two"), new Node ("three") }; Console.WriteLine(TreeView(Records, r => r.Children, r => r.Data));
以下是上述代码的结果。
- one
- one-one
- one-one-one
- one-one-two
- one-one-three
one-two one-three two three