2015-01-04 3 views
2

부모와 자식의 트리 구조를 만들려고합니다. 문제는 난 단지 다른 곳 어린이와 부모 클래스에서 아이의 부모를 asign 수 있기를 원하고 있다는 것입니다하지 않은 C#을 프로그래머가부모와 자식이있는 트리 구조

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 
    } 
} 

를, 내가 좋아하는 (친구를 사용하는 들었다 C++에서는 구현되지 않았지만 다른 모든 솔루션은 실패했습니다.

+0

보호를 사용해보십시오. – idstam

+1

어떻게 도움이 될까요? – zmbq

+0

Protected는 이미 시도한 것들 중 하나이지만, 하위 클래스에서 다른 부모 인스턴스의 보호 된 필드를 사용할 수는 없습니다. – 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개인 구현을 작성합니다. 코드에서 개인 구현을 호출하지만 IChildIParent 만 반환하십시오.

주 - 개인 클래스는 C#에서 중첩 된 클래스입니다. 나는이 클래스들이 어떤 클래스에 중첩되어야 하는지를 말할 수 없다 - 그것은 당신의 프로젝트에 달려있다. 합리적인 장소가 없으면 자식/부모 DLL 라이브러리를 만들고 공용 인터페이스를 구현하는 internal Child 및 Parent 클래스를 가질 수 있습니다.

덧붙여서 나는 ParentChild 클래스가 모두있는 이유를 이해하지 못합니다. 특히 Child가 Parent에서 파생 된 이유는 아닙니다. Node 클래스가 하나있는 경우 개인 설정자와 함께 Parent 속성을 가질 수 있으며 걱정할 필요가 없습니다.

+0

'노드'의 문제점은 하위 노드 만있는 루트가 없기 때문에 부모 개체를 생성 한 이유입니다. 하지만 Node 클래스가 있어야합니다. 어떻게 루트를 구현합니까? – Safron

+1

루트의 부모는 null로 설정됩니다. 클래스 나 코드를 사용하는 것이 중요하다면 노드에 IsRoot() 메서드를 노출하여 부모가 있는지 확인하고 부울을 반환합니다. –

+0

@JoelGregory가 말한 바. 이것이 트리 노드가 일반적으로 구현되는 방식입니다. – zmbq

1

ParentChild이 다른 클래스가 필요하면 이벤트를 사용하여 수행 할 수 있습니다. Child이 추가되고 제거 될 때마다 Parent 클래스에서 이벤트를 제공하도록 만든 다음 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; } 
    } 
} 

가 (물론, 다음, 모든 개인이 될 수 있으며,이 메커니즘은 않을 것