C# 带泛型的嵌套类

C# 带泛型的嵌套类,c#,generics,nested-class,C#,Generics,Nested Class,我目前正在从事的项目需要我创建一个树数据结构。 下面是我如何尝试实现此功能的示例。我决定创建一个子节点集合作为嵌套类,因为它允许我在其Add()方法中设置节点父级,同时保持父级setter私有,因此从节点派生的类或同一程序集中的其他类无法直接访问它 class Node<T> where T : Node<T> { private T mParent; private ChildNodeCollection<T> mChildren; publi

我目前正在从事的项目需要我创建一个树数据结构。 下面是我如何尝试实现此功能的示例。我决定创建一个子节点集合作为嵌套类,因为它允许我在其Add()方法中设置节点父级,同时保持父级setter私有,因此从节点派生的类或同一程序集中的其他类无法直接访问它

class Node<T> where T : Node<T>
{
  private T mParent;
  private ChildNodeCollection<T> mChildren;

  public T Parent
  {
    get{return this.InnerParent;}
  }

  private T InnerParent
  {
     get{return this.mParent;}
     set {this.mParent = value;}
  }

  public Node()
  {
      this.mChildren = new ChildNodeCollection<T>(this);
  }

  class ChildNodeCollection<U> where U : T
  {
       private U mParent;

       public U CollectionParent
       {
           get{return this.mParent;}
       }

       public ChildNodeCollection(U parent)
       {
           this.mParent = parent;
       }


        public void Add(U item)
        {
            item.InnerParent = this.CollectionParent;

            ...
        }

  }
}

我想它不能算出t是节点,即使我在类定义中指定了。我很好奇是否有人知道如何以不同的方式来实现这一点,使我能够在将节点添加到集合时设置其父节点,而不必使用内部访问修饰符过多地公开节点的父属性。

在任何情况下,使用构造函数创建泛型对象时都需要显式指定类型参数,所以你需要写一些东西,比如:

this.mChildren = new ChildNodeCollection<T>(this);
我猜您最初的目标(使用
T:Node
constraint)是使用继承来定义更具体的节点类型。然后,您希望检索静态键入为
T
(即您的特定节点类型)的子节点(或父节点)。我可能错了,但我严重怀疑.NET泛型能否表达这一点


我认为将
Node
用作表示包含
T
类型值的节点的类型比使用继承要容易得多

您指定的约束表示U必须从T继承


当您尝试执行此操作时,
this.mChildren=new ChildNodeCollection(this)
U被隐式定义为此(
节点
)的类型。但是没有定义T

我相信这可以通过使用
protected

class Node<T> 
{
    protected Node<T> _parent;
    protected List<Node<T>> _children;

    protected T _value;

    protected Node() { }

    public Node(T value)
    {
        _parent = null;
        _value = value;
        _children = new List<Node<T>>();
    }

    public void AddChild(Node<T> child) 
    {            
        child._parent = this;
        _children.Add(child);
    }
}

class NaughtyNode : Node<int>
{
    //Naughty nodes dont have parents, only kids

    public NaughtyNode(int value)
    {
        _value = value;
        _children = new List<Node<T>>();
    }

    public void BeNaughty()
    {
        Node<int> victim = new Node<int>(1);
        victim._parent = this; //Does not work, cannot access
    }

    public void AddChild(NaughtyNode child)
    {
        _children.Add(child);
    }
}
类节点
{
受保护节点\u父节点;
受保护儿童名单;
保护T_值;
受保护节点(){}
公共节点(T值)
{
_parent=null;
_价值=价值;
_children=新列表();
}
公共void AddChild(节点子节点)
{            
child.\u parent=this;
_添加(child);
}
}
类noutynode:Node
{
//淘气的节点没有父母,只有孩子
公共NoutyNode(int值)
{
_价值=价值;
_children=新列表();
}
公开无效
{
节点受害者=新节点(1);
受害者。_parent=this;//不工作,无法访问
}
public void AddChild(noutynode child)
{
_添加(child);
}
}

受保护的
仅允许
节点内的代码访问它
NootyNode
无法看到
节点的
\u父节点

Hmmm,您不应该将节点作为父节点,将节点集合作为子节点吗?还有,你不应该有一个泛型构造函数吗?如果父节点没有任何真正区别于子节点的特性,那么你可以使你想要在节点之间公开的方法受到保护,同时保持常规节点方法,如获取父节点public@FlyingStreudel具体在哪里,你能说得更具体些吗?顺便说一句,我使用的是.NET 2,因此在更高版本中添加到泛型中的任何新功能都不能使用。有关更多详细信息,请参阅我的答案,虽然它不是100%符合2.0,但我认为您在这里混用了一些东西。受保护修饰符允许访问从节点继承的所有类,因此NoutyNode可以访问并更改它的父类。Internal允许访问在同一程序集中定义的所有类,因此如果Nootynode在与Node相同的程序集中定义,则Nootynode可以更改其子集合,而无需将childrens\u parent设置为null,这可能会导致不一致。是的,我完全同意。您不想使用内部。但据我所知,NoutyNode无法访问节点的父节点。。。要快速编译测试…尝试从NoutyNode访问节点的
\u父节点
会产生:
无法通过类型为“StackNotebook.Node”的限定符访问受保护的成员“StackNotebook.Node.\u parent”;限定符的类型必须为“StackNotebook.NoutyNode”
Hmm。。。但我仍然不太明白为什么它不能识别Node,因为我将尝试将它更改为这个;一旦我回家。
public Node() {
  this.mChildren = new ChildNodeCollection(this);
}

class ChildNodeCollection {
  private Node<T> mParent;

  public ChildNodeCollection(Node<T> parent) {
    this.mParent = parent;
  }
}
class Node<T> 
{
    protected Node<T> _parent;
    protected List<Node<T>> _children;

    protected T _value;

    protected Node() { }

    public Node(T value)
    {
        _parent = null;
        _value = value;
        _children = new List<Node<T>>();
    }

    public void AddChild(Node<T> child) 
    {            
        child._parent = this;
        _children.Add(child);
    }
}

class NaughtyNode : Node<int>
{
    //Naughty nodes dont have parents, only kids

    public NaughtyNode(int value)
    {
        _value = value;
        _children = new List<Node<T>>();
    }

    public void BeNaughty()
    {
        Node<int> victim = new Node<int>(1);
        victim._parent = this; //Does not work, cannot access
    }

    public void AddChild(NaughtyNode child)
    {
        _children.Add(child);
    }
}