Вложенный класс с генериками - PullRequest
3 голосов
/ 26 мая 2011

Проект, над которым я сейчас работаю, требует от меня создания древовидной структуры данных. Ниже приведен пример того, как я пытался добиться этой функциональности. Я решил создать коллекцию дочерних узлов как вложенный класс, так как он позволяет мне устанавливать родительский узел в его методе Add (), сохраняя приватность родительского установщика, чтобы классы, производные от узла или других классов в той же сборке, не могли получить прямой доступ к нему.

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;

            ...
        }

  }
}

Этот код не компилируется. Он жалуется на строку this.mChildren = new ChildNodeCollection(this) в конструкторе Node. Он выбрасывает эти две ошибки.

Error   35  The best overloaded method match for Node<T>.ChildNodeColllection<T>.ChildNodeColllection(T)' has some invalid arguments

Error   36  Argument '1': cannot convert from Node<T> to T

Полагаю, не может получиться, что T - это Node, хотя я указал это в определении класса. Мне любопытно, если у кого-нибудь есть идеи, как это можно сделать по-другому, что позволило бы мне устанавливать родителя Node при добавлении его в коллекцию, не раскрывая слишком много свойства Node's Parent с помощью внутреннего модификатора доступа.

Ответы [ 3 ]

3 голосов
/ 26 мая 2011

В любом случае вам нужно явно указать аргумент типа при создании универсального объекта с помощью конструктора, поэтому вам нужно написать что-то вроде:

this.mChildren = new ChildNodeCollection<T>(this);

Это не будет работать, потому что тип this - это Node<T>, а не T (что и требуется конструктору).Я думаю, что самый простой способ исправить это - сохранить родителя как Node<T> вместо использования универсального параметра.

Соответствующие части кода будут выглядеть так:

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

class ChildNodeCollection {
  private Node<T> mParent;

  public ChildNodeCollection(Node<T> parent) {
    this.mParent = parent;
  }
}

IПредположим, что вашей первоначальной целью (с использованием ограничения T : Node<T>) было использование наследования для определения более конкретных типов узлов.Затем вы хотите получить детей (или родителей), статически типизированных как T (то есть ваш конкретный тип узла).Я могу ошибаться, но я серьезно сомневаюсь, что это может быть выражено с помощью обобщений .NET.

Я думаю, что гораздо проще использовать Node<T> как тип, представляющий узел, который содержит ваше значение типа T вместо использования наследования.

0 голосов
/ 26 мая 2011

Я считаю, что это можно решить с помощью 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);
    }
}

protected разрешает доступ к коду только в пределах Node<T>.NaughtyNode не может видеть Node<T> _parent.

0 голосов
/ 26 мая 2011

Вы указываете ограничение, которое говорит, что U должно наследоваться от T .

Когда вы пытаетесь сделать this.mChildren = new ChildNodeCollection(this) U неявно определяется как тип этого (Node<T>).Но T не определен.

...