【问题标题】:Implementing a tree in c# managing parent-child在c#中实现树管理父子
【发布时间】:2009-01-13 16:29:12
【问题描述】:

我正在实现一棵树,将其视为文件夹结构,因此我有一个如下所示的类:

public class Folder
{
    //Various Props like Name etc.
    public IList<Folder> Children{get;}
    public Folder Parent {get;}
}

现在我想要的是能够在树上上下走动,所以给定一个根我可以找到一个叶子,给定一个叶子我可以找到根节点。所以每个孩子都需要一个父母。现在的问题是向树中添加新节点的最佳方法是什么。我过去使用过两种解决方案:

  1. 在Folder 中添加AddChild(Folder) 方法来处理添加文件夹,并且可以设置父级。这个问题是我现在必须锁定我的 Children 集合,这样你就不能绕过这个方法。
  2. 创建我自己的 Children 集合,该集合将被返回给实例的引用,因此它可以处理在添加时设置父级。这个问题我必须实现一个新的集合。
  3. 使用在添加或删除项目时包含事件的集合。

我很好奇人们通常使用什么模式,然后是否有人对我的特定用例有任何建议。我正在使用 nHibernate 将我的树持久化到 SQL 服务器。我宁愿不实现一个自定义集合,因为它需要很多代码才能使它适用于我的应用程序的一小部分。

【问题讨论】:

  • 我正在寻找 nHibernate 和更一般的想法...有一篇很好的帖子,其中包含有人删除的收藏...

标签: c# nhibernate design-patterns tree


【解决方案1】:

看了on MSDN之后,你可以试试这个:

List<Folder> children;

public ReadOnlyCollection<Folder> Children
{
    get { return this.children.AsReadOnly(); }
}

如果您的私有成员必须声明为 IList,那么我们可以将其复制到列表中,然后将其返回。但我真的不认为将具体实现用作私有成员有问题。稍后更改实现不会破坏兼容性。

IList<Folder> children;

public ReadOnlyCollection<Folder> Children
{
    get 
    { 
        return new List<Folder>(this.children).AsReadOnly(); 
    }
}

【讨论】:

  • 仅当您使用列表时;-) IList 不支持。
  • 是的。但据我所知,没有指定只读列表的接口。因此,您要么使用更通用的 IEnumerable 并失去索引。或返回 ReadOnlyList 的后代并更改您的私有实现。任何其他解决方案都需要编写自己的类/接口
  • 我添加了一个满足您所有要求的新解决方案 :-)
【解决方案2】:

使用数字 1,但将您的 Children 属性设置为 IEnumerable,以便用户无法添加到集合中。

【讨论】:

    【解决方案3】:

    就个人而言,我会采用方法 1。允许客户端代码直接操作 Children 集合在任何情况下都违反封装,因此“锁定”Children 集合是正确的事情™。

    保持节点关系正确的“正确”策略取决于客户的需求。我假设在这种特定情况下,您希望客户端能够自己更改子节点,但不能更改 Children 集合。如果是这样的话,我认为 Rob Prouse 的建议(让 Children 属性返回一个 IEnumerable)可能是最好的选择。在其他情况下,ReadOnlyCollection 可能会更好。

    【讨论】:

    • 那么你将如何防止他们修改集合?你使用什么策略?只读集合?归还收藏副本?
    • @Josh:返回 IEnumerable 的一种方法:public IEnumerable Children { get { foreach (Folder child in children) { yield return child; } } }
    【解决方案4】:

    实现自定义集合的工作量很大;对仅公开两个或三个方法的现有集合类实现包装器不是。从您对 JayArr 的回复来看,这似乎就是您要寻找的东西。比如:

    public class ChildCollection
    {
       // _Children is maintained by the Folder class, hence the internal access specifier
       internal Dictionary<KeyType, Folder> _Children = new Dictionary<KeyType, Folder>;
    
       public this[KeyType key]
       {
          get
          {
              return _Children[key];
          }
       }
    
       public IEnumerable<KeyType> Keys
       {
          get
          {
             return _Children.Keys;
          }
       }
    }
    

    【讨论】:

      【解决方案5】:

      我会选择选项 1,然后让 Children 属性看起来像这样:

          public IEnumerable<Folder> Children
          {
              get { return this.children.GetEnumerator(); }
          }
      

      现在必须调用 AddChild 来添加孩子。该集合不可访问。

      【讨论】:

      • 嗯,只要客户不想索引到 IList...如果您的孩子是一本字典,它就会崩溃...
      猜你喜欢
      • 2012-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-06
      • 1970-01-01
      • 2014-03-31
      相关资源
      最近更新 更多