在c#中实现树管理父子关系

在c#中实现树管理父子关系,c#,nhibernate,design-patterns,tree,C#,Nhibernate,Design Patterns,Tree,我正在实现一个树,将其视为一个文件夹结构,因此我有一个类似以下的类: public class Folder { //Various Props like Name etc. public IList<Folder> Children{get;} public Folder Parent {get;} } 公共类文件夹 { //各种道具,如名字等。 公共IList子项{get;} 公用文件夹父项{get;} } 现在我想要的是能够在树上走来走去,这样给定一

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

public class Folder
{
    //Various Props like Name etc.
    public IList<Folder> Children{get;}
    public Folder Parent {get;}
}
公共类文件夹
{
//各种道具,如名字等。
公共IList子项{get;}
公用文件夹父项{get;}
}
现在我想要的是能够在树上走来走去,这样给定一个根,我就能找到一片叶子,给定一片叶子,我就能找到根节点。所以每个孩子都需要一个父母。现在的问题是,向树中添加新节点的最佳方式是什么。我过去使用过两种解决方案:

  • 将AddChild(Folder)方法添加到处理添加文件夹的文件夹,并可以设置父文件夹。问题是我现在必须锁定我的Children集合,这样你就不能绕过这个方法
  • 创建我自己的子集合,该集合将被返回到实例的引用,以便它可以处理在add上设置父集合的操作。问题是我必须实现一个新的集合
  • 使用在添加或删除项目时包含事件的集合

  • 我很好奇人们通常使用什么模式,然后如果有人对我的特定用例有任何建议。我正在使用nHibernate将我的树持久化到SQL server。我不希望实现自定义集合,因为它需要大量的代码才能使它在我的应用程序中的一小部分工作

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


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

    我会选择选项1,然后使Children属性如下所示:

        public IEnumerable<Folder> Children
        {
            get { return this.children.GetEnumerator(); }
        }
    
    公共IEnumerable子项
    {
    get{返回this.children.GetEnumerator();}
    }
    

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

    使用数字1,但要使您的子属性IEnumerable,以便用户无法添加到集合。

    查看后,您可以尝试以下操作:

    List<Folder> children;
    
    public ReadOnlyCollection<Folder> Children
    {
        get { return this.children.AsReadOnly(); }
    }
    
    列出子项;
    公共只读集合子项
    {
    获取{返回this.children.AsReadOnly();}
    }
    
    如果您的私有成员必须声明为IList,那么我们可以将其复制到列表中,然后返回它。但我真的不认为作为私有成员使用具体实现有什么问题。以后更改实现不会破坏兼容性

    IList<Folder> children;
    
    public ReadOnlyCollection<Folder> Children
    {
        get 
        { 
            return new List<Folder>(this.children).AsReadOnly(); 
        }
    }
    
    IList儿童;
    公共只读集合子项
    {
    得到
    { 
    返回新列表(this.children).AsReadOnly();
    }
    }
    
    实现自定义集合需要大量工作;实现一个只公开两个或三个方法的现有集合类的包装器是不可能的。从你对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;
          }
       }
    }
    
    公共类ChildCollection
    {
    //_子项由Folder类维护,因此是内部访问说明符
    内部字典_Children=新字典;
    公开此[密钥类型密钥]
    {
    得到
    {
    返回子项[键];
    }
    }
    公共IEnumerable密钥
    {
    得到
    {
    返回_Children.key;
    }
    }
    }
    
    那么您如何防止他们修改集合?你用什么策略?只读集合?返回集合副本?@Josh:返回IEnumerable的一种方法:public IEnumerable子项{get{foreach(子项中的文件夹子项){yield Return child;}}}嗯,只要客户端不想索引到IList,nice就可以正常工作……如果您的孩子是一本词典,它就会崩溃……只有当您使用列表时;-)IList不支持这一点。没错。但就我所见,没有一个接口指定一个只读列表。所以要么使用更通用的IEnumerable,要么就失去索引。或者返回ReadOnlyList的子代并更改您的私有实现。任何其他解决方案都需要编写您自己的类/接口我添加了一个新的解决方案,适合您的所有需求:-)我正在寻找nHibernate和更一般的想法…有一个很好的帖子,其中有人删除了一个集合。。。