实现父子类层次结构

发布于 2024-07-27 13:29:31 字数 1520 浏览 5 评论 0 原文

我发现很难找到一个关于如何实现父子层次结构类的合适示例。 我有一个 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);
    }
}

I'm finding it difficult to find a decent example on how to implement a parent-child hierarchy class.
I have a treeView control that I want to convert into a class hierarchy, adding extra data to each node and be able to easely iterate over each parent's nodes using IEnumerable.

public IEnumerable<Node> GetAllChildsFromParent(Node parent)
{
    foreach (Node node in parent.NodeChildsCollection)
    {
        yield return node;
    }
}

I already have implemented the following piece of code but got stuck and don't really
have a clue whether I am on the right track or not? How should I proceed to complete this ?

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

栀子花开つ 2024-08-03 13:29:31

您将节点的职责与集合的职责混合在一起。 看看您如何在集合中设置父级? 它不是有父级的集合;而是有父级的集合。 它的节点。

我将像这样构造我的节点:

public class Node
{
  public Node Parent {get;set;} // null for roots

  public NodeCollection Children {get; private set;}

  public Node() 
  { 
    Children = new NodeCollection(); 
    Children.ChildAdded += ChildAdded;
    Children.ChildRemoved += ChildRemoved;
  };
  private void ChildAdded(object sender, NodeEvent args)
  {
    if(args.Child.Parent != null)
      throw new ParentNotDeadYetAdoptionException("Child already has parent");
    args.Child.Parent = this;
  }
  private void ChildRemoved(object sender, NodeEvent args)
  {
    args.Child.Parent = null;
  }
}

NodeCollection 看起来像

public class NodeCollection : INodeCollection {/*...*/}

,而 INodeCollection 将是:

public interface INodeColleciton : IList<Node>
{
  event EventHandler<NodeEvent> ChildAdded;
  event EventHandler<NodeEvent> ChildRemoved;
}

集合职责位于节点的 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:

public class Node
{
  public Node Parent {get;set;} // null for roots

  public NodeCollection Children {get; private set;}

  public Node() 
  { 
    Children = new NodeCollection(); 
    Children.ChildAdded += ChildAdded;
    Children.ChildRemoved += ChildRemoved;
  };
  private void ChildAdded(object sender, NodeEvent args)
  {
    if(args.Child.Parent != null)
      throw new ParentNotDeadYetAdoptionException("Child already has parent");
    args.Child.Parent = this;
  }
  private void ChildRemoved(object sender, NodeEvent args)
  {
    args.Child.Parent = null;
  }
}

And the NodeCollection would look like

public class NodeCollection : INodeCollection {/*...*/}

and INodeCollection would be:

public interface INodeColleciton : IList<Node>
{
  event EventHandler<NodeEvent> ChildAdded;
  event EventHandler<NodeEvent> ChildRemoved;
}

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.

千秋岁 2024-08-03 13:29:31

我找到了这个博客文章在尝试解决相同问题时非常有用。

I found the this blog article quite useful when attempting to solve the same problem.

万劫不复 2024-08-03 13:29:31

如果您想将树状数据结构的概念与存储的特定数据分开,请通过使其通用来使其成为通用容器。

另外,如果树只有一个根,则树节点本身就是树节点的集合,因此(与任何集合一样)添加项目的方法应称为 Add。 仅当您经常拥有树集合时,将子集合设为单独的对象才有意义。 这种情况发生在 Windows UI 中的 TreeView 中,因为 TreeView 的根包含多个节点而不是单个根树节点。 然而,在 XML 或 HTML DOM 之类的东西中,总是有一个根,所以我认为更简单的东西是合适的。

最后,您不需要使用 yield return 实现 IEnumerable 内容 - 只需转发到标准容器的实现即可。

public class TreeNode<TValue> : IEnumerable<TreeNode<TValue>>
{
    private List<TreeNode<TValue>> _children = new List<TreeNode<TValue>>();

    public TreeNode<TValue> Parent { get; private set; }

    public void Add(TreeNode<TValue> child)
    {
        _children.Add(child);
        child.Parent = this;
    }

    public void Remove(TreeNode<TValue> child)
    {
        _children.Remove(child);
        child.Parent = null;
    }

    public IEnumerator<TreeNode<TValue>> GetEnumerator()
    {
        return _children.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _children.GetEnumerator();
    }      
}

事实上,您可以让它实现 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 with yield return - just forward to a standard container's implementation.

public class TreeNode<TValue> : IEnumerable<TreeNode<TValue>>
{
    private List<TreeNode<TValue>> _children = new List<TreeNode<TValue>>();

    public TreeNode<TValue> Parent { get; private set; }

    public void Add(TreeNode<TValue> child)
    {
        _children.Add(child);
        child.Parent = this;
    }

    public void Remove(TreeNode<TValue> child)
    {
        _children.Remove(child);
        child.Parent = null;
    }

    public IEnumerator<TreeNode<TValue>> GetEnumerator()
    {
        return _children.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _children.GetEnumerator();
    }      
}

In fact you could make it implement IList<TreeNode<TValue>> and forward all the methods on to the list, with appropriate manipulation of the Parent property whenever adding/removing children.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文