2015-01-04 16 views
2

Я пытаюсь создать древовидную структуру родителей и детей. Проблема заключается в том, что я только хочу, чтобы иметь возможность Asign родителя ребенка в дочерних и родительских классах, и нигде больше:Структура деревьев с родителями и детьми

public class Parent 
{ 
    public static Parent Root = new Parent(); 

    private List<Child> children = new List<Child>(); 
    public ReadOnlyCollection<Child> Children 
    { 
     get { return children.AsReadOnly(); } 
    } 

    public void AppendChild(Child child) 
    { 
     child.Parent.RemoveChild(child); 
     child.children.Add(child); 
     child.Parent = this; //I need to asign the childs parent in some way 
    } 
    public void RemoveChild(Child child) 
    { 
     if (this.children.Remove(child)) 
     { 
      child.Parent = Parent.Root; //here also 
     } 
    } 
} 
public class Child : Parent 
{ 
    private Parent parent = Parent.Root; 
    public Parent Parent 
    { 
     get { return this.parent; } 
     private set { this.parent = value; } //nothing may change the parent except for the Child and Parent classes 
    } 
} 

By A # программиста не-C, мне сказали, чтобы использовать друг (например, в C++), но они не реализованы на C#, и все мои другие решения не удались.

+0

Попробуйте использовать защищенные. – idstam

+1

Как это поможет? – zmbq

+0

Охраняемая является одной из вещей, которые я уже пробовал, но я не могу использовать защищенное поле другого экземпляра родителя, а не самого себя в дочернем классе. – Safron

ответ

2

Это может не ответить на ваш вопрос, но это альтернатива. Это структура узла и вы могли бы использовать что-то вроде этого:

public class Node 
{ 
    private Node _parent; 
    private List<Node> _children = new List<Node>(); 

    public Node(Node parent) 
    { 
     _parent = parent 
    } 

    public ReadOnlyCollection<Node> Children 
    { 
     get { return _children.AsReadOnly(); } 
    } 

    public void AppendChild(Node child) 
    { 
     // your code 
    } 

    public void RemoveChild(Node child) 
    { 
     // your code 
    } 
} 

Я вижу @zmbq только отредактирован, чтобы предложить что-то подобное.

+0

Вы все предложили это решение, поэтому было трудно выбрать, какой из них принять, но я хочу поблагодарить всех вас за то, что вы так быстро ответили. – Safron

3

Если вы также можете нести ответственность за создание детей и родителей (для этого вы можете предоставить фабричные методы), для этого вы можете использовать интерфейсы и частные классы.

interface IChild 
{ 
    // methods and properties for child, including 
    IParent Parent { get; } // No setter. 
} 

interface IParent 
{ 
    // Methods and properties for parent 
} 

Теперь вы создаете реализацию в частного из IChild, который также имеет родительскую сеттера. В вашем кодовом вызове выполните вашу частную реализацию, но верните только IChild и IParent.

Примечание - частные классы представляют собой вложенные классы в C#. Я не могу сказать вам, в каком классе эти классы должны быть вложенными - это зависит от вашего проекта. Если такого разумного места нет, вы можете создать дочернюю/родительскую библиотеку DLL и иметь internal классы Child и Parent, реализующие публичные интерфейсы.

Кстати, я не понимаю, почему у вас есть и классы Parent, и Child, и особенно не то, почему Child происходит от родителя. Если у вас есть один класс Node, вы можете иметь Parent недвижимость с частным сеттером, и не беспокойтесь об этом.

+0

Проблема с «узлом» заключается в том, что нет корня с только дочерними элементами, поэтому для этого я создал родительский объект. Но должен ли я иметь класс Node, как мне реализовать корень? – Safron

+1

У вашего корня просто будет родительский набор равным null. Если это важно для вашего класса или кода потребления, возможно, вы получите метод IsRoot() на вашем узле, который проверяет, имеет ли он родительский элемент и возвращает логическое значение. –

+0

Что сказал @JoelGregory. Вот как обычно реализуются узлы дерева. – zmbq

1

Если вам нужны Parent и Child, чтобы быть разными классами, вы можете сделать это, используя события. Сделайте класс Parent событием всякий раз, когда добавляется и удаляется Child, затем сделайте так, чтобы Child выслушал это и правильно установил свой собственный родитель. Эффективно список ребенок в Parent становится первичными данными и родитель становится обратной ссылкой, например, так:

public class ParentChangedEventArgs : EventArgs 
{ 
    public Parent Parent { get; private set; } 
    public Child Child { get; private set; } 

    public ParentChangedEventArgs(Parent parent, Child child) 
    { 
     this.Parent = parent; 
     this.Child = child; 
    } 
} 

public class Parent 
{ 
    public static event EventHandler<ParentChangedEventArgs> ParentChanged; // Could be internal or protected. 

    public static Parent Root = new Parent(); // SHOULDN'T THIS BE READONLY? 

    private readonly List<Child> children = new List<Child>(); 

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

    public void AppendChild(Child child) 
    { 
     var oldParent = child.Parent; 
     if (oldParent == this) 
      return; 
     oldParent.children.Remove(child); 
     this.children.Add(child); 
     if (ParentChanged != null) 
      ParentChanged(oldParent, new ParentChangedEventArgs(this, child)); 
    } 

    public void RemoveChild(Child child) 
    { 
     Root.AppendChild(child); // Removing a child means adding it to the root. 
    } 
} 

public class Child : Parent 
{ 
    static Child() 
    { 
     Parent.ParentChanged += new EventHandler<ParentChangedEventArgs>(Parent_ChildChanged); 
    } 

    static void Parent_ChildChanged(object sender, ParentChangedEventArgs e) 
    { 
     var child = e.Child; 
     child.Parent = e.Parent; 
    } 

    private Parent parent = Parent.Root; 

    public Parent Parent 
    { 
     get { return this.parent; } 
     private set { this.parent = value; } 
    } 
} 

(Конечно, если бы они были тем же классом, то все может быть частным и этот механизм не будет необходимо.)