实现父子类层次结构
我发现很难找到一个关于如何实现父子层次结构类的合适示例。 我有一个 treeView 控件,我想将其转换为类层次结构,向每个节点添加额外的数据,并能够使用 IEnumerable 轻松迭代每个父节点的节点。
public IEnumerable<Node> GetAllChildsFromParent(Node parent)
{
foreach (Node node in parent.NodeChildsCollection)
{
yield return node;
}
}
我已经实现了下面的代码,但卡住了,并没有真正实现 知道我是否走在正确的道路上吗? 我应该如何继续完成这个?
public class NodeChildsCollection : IEnumerable<Node>
{
IList<Node> nodeCollection = new List<Node>();
Node parent;
public Node Parent
{
get { return parent; }
set { parent = value; }
}
public NodeChildsCollection()
{
}
public void AddNode(Node parent, Node child)
{
this.parent = parent;
nodeCollection.Add(child);
}
#region IEnumerable<Node> Members
public IEnumerator<Node> GetEnumerator()
{
foreach (Node node in nodeCollection)
{
yield return node;
}
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
public class Node
{
NodeChildsCollection nodeChildsCollection = new NodeChildsCollection();
public Node Parent
{
get { return nodeChildsCollection.Parent; }
set { nodeChildsCollection.Parent = value; }
}
public void AddChild(Node child)
{
nodeChildsCollection.AddNode(this, child);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您将节点的职责与集合的职责混合在一起。 看看您如何在集合中设置父级? 它不是有父级的集合;而是有父级的集合。 它的节点。
我将像这样构造我的节点:
NodeCollection 看起来像
,而 INodeCollection 将是:
集合职责位于节点的 Child 集合属性上。 当然,您可以让节点实现 INodeCollection,但这是编程品味的问题。 我更喜欢拥有 Children 公共财产(这是框架的设计方式)。
通过此实现,您不需要实现“GetChildren”方法; 公共儿童财产为所有人提供它们。
You're mixing the responsibilities of the Node with the responsibilities of the collection. See how you're setting the parent in the collection? It's not the collection that has a parent; its the node.
I'd structure my nodes like thus:
And the NodeCollection would look like
and INodeCollection would be:
The collection responsibilities are on the Child collection property of the Node. You can, of course, have node implement INodeCollection, but that's a matter of programming tastes. I prefer to have the Children public property (its how the framework is designed).
With this implementation you don't need to implement a "GetChildren" method; the public Children property provides them for all.
我找到了这个博客文章在尝试解决相同问题时非常有用。
I found the this blog article quite useful when attempting to solve the same problem.
如果您想将树状数据结构的概念与存储的特定数据分开,请通过使其通用来使其成为通用容器。
另外,如果树只有一个根,则树节点本身就是树节点的集合,因此(与任何集合一样)添加项目的方法应称为
Add
。 仅当您经常拥有树集合时,将子集合设为单独的对象才有意义。 这种情况发生在 Windows UI 中的 TreeView 中,因为 TreeView 的根包含多个节点而不是单个根树节点。 然而,在 XML 或 HTML DOM 之类的东西中,总是有一个根,所以我认为更简单的东西是合适的。最后,您不需要使用
yield return
实现IEnumerable
内容 - 只需转发到标准容器的实现即可。事实上,您可以让它实现 IList> 并将所有方法转发到列表,并在添加/删除时对
Parent
属性进行适当的操作孩子们。If you want to separate the notion of a tree-like data structure from the specific data being stored, make it a general purpose container by making it generic.
Also, if the tree has a single root, a treenode is itself a collection of treenodes, so (like any collection) the method for adding an item should be called
Add
. Making the child collection a separate object would only make sense if you often have collections of trees. This occurs in TreeViews in the Windows UI because the root of a TreeView contains multiple nodes rather than a single root treenode. However, in something like the XML or HTML DOM, there's always a single root, and so I think something simpler is appropriate.Finally, you don't need to implement the
IEnumerable
stuff withyield return
- just forward to a standard container's implementation.In fact you could make it implement
IList<TreeNode<TValue>>
and forward all the methods on to the list, with appropriate manipulation of theParent
property whenever adding/removing children.