与父母和孩子的树结构

时间:2015-01-04 09:13:26

标签: c# parent-child friend tree-structure

我正在尝试制作父母和孩子的树形结构。问题是我只希望能够在子类和父类中对子项的父项进行设置,而不是其他任何地方:

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#程序员,我被告知要使用朋友(比如C ++),但这些都没有在C#中实现,而我所有其他解决方案都失败了。

3 个答案:

答案 0 :(得分: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属性,而不用担心它。

答案 1 :(得分: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刚刚编辑过一些类似的东西。

答案 2 :(得分:1)

如果您需要ParentChild为不同的类,则可以使用事件执行此操作。每当添加和删除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; }
    }
}

(当然,如果他们是同一个班级,那么一切都可以是私人的,这个机制就没有必要了。)