3 Stimmen

Verschachtelte Klasse mit Generika

Für das Projekt, an dem ich derzeit arbeite, muss ich eine Baumdatenstruktur erstellen. Unten ist ein Beispiel, wie ich versucht habe, diese Funktionalität zu erreichen. Ich habe mich entschieden, eine Sammlung von Kindknoten als verschachtelte Klasse zu erstellen, da dies mir erlaubt, Nodes Elternteil in seiner Add()-Methode zu setzen, während ich den Eltern-Setter privat halte, so dass von Node abgeleitete Klassen oder andere Klassen in derselben Assembly keinen direkten Zugriff darauf erhalten können.

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;

            ...
        }

  }
}

Dieser Code lässt sich jedoch nicht kompilieren. Er beschwert sich über this.mChildren = new ChildNodeCollection(this) Zeile im Node-Konstruktor. Es werden diese beiden Fehler ausgelöst.

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

Ich schätze, es kann nicht herausfinden, dass T Node ist, obwohl ich das in der Klassendefinition angegeben habe. Ich bin neugierig, wenn jemand eine Idee hat, wie dies anders in einer Weise, die mir erlauben würde, Node's Elternteil zu setzen, wenn es zu Sammlung hinzufügen, ohne Node's Parent-Eigenschaft zu viel mit internen Zugriffsmodifikator freizulegen getan werden könnte.

3voto

Tomas Petricek Punkte 233658

In jedem Fall müssen Sie das Typargument explizit angeben, wenn Sie ein generisches Objekt mit Hilfe eines Konstruktors erstellen, also müssen Sie etwas schreiben wie:

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

Das wird nicht funktionieren, weil die Art der this es Node<T> und nicht T (das ist, was der Konstruktor erfordert). Ich denke, der einfachste Weg, dies zu beheben, ist das Speichern des Elternteils als Node<T> anstatt einen allgemeinen Parameter zu verwenden.

Die entsprechenden Teile des Codes würden wie folgt aussehen:

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

class ChildNodeCollection {
  private Node<T> mParent;

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

Ich vermute, dass Ihr ursprüngliches Ziel (mit der Verwendung des T : Node<T> constraing) war die Verwendung von Vererbung, um spezifischere Arten von Knoten zu definieren. Dann möchte man statisch typisierte Kinder (oder Eltern) zurückerhalten als T (d.h. Ihren spezifischen Knotentyp). Ich kann falsch sein, aber ich bezweifle ernsthaft, dass dies mit .NET Generics ausgedrückt werden kann.

Ich denke, es ist viel einfacher zu benutzen Node<T> als einen Typ, der einen Knoten repräsentiert, der Ihren Wert vom Typ T anstatt die Vererbung zu verwenden.

0voto

Yochai Timmer Punkte 46099

Sie geben eine Bedingung an, die besagt, dass U muss erben von T .

Wenn Sie versuchen, die this.mChildren = new ChildNodeCollection(this) U ist implizit als der Typ dieser ( Node<T> ). Pero T ist nicht definiert.

0voto

FlyingStreudel Punkte 4324

Ich glaube, dass dieses Problem durch die Verwendung der folgenden Methoden gelöst werden könnte 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);
    }
}

El protected erlaubt nur Code innerhalb von Node<T> um darauf zuzugreifen. NaughtyNode kann nicht sehen Node<T> 's _parent .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X