2

我正在尝试制作父母和孩子的树状结构。问题是我只想能够在子类和父类中分配孩子的父母,而不是其他地方:

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# 中实现,并且我的所有其他解决方案都失败了。

4

3 回答 3

3

如果您还可以负责实际创建子项和父项(您可以为此提供工厂方法),则可以使用接口和私有类来实现这一点。

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

interface IParent
{
   // Methods and properties for parent
}

现在,您创建了一个私有实现,IChild它也有一个 Parent 设置器。在您的代码中调用您的私有实现,但仅返回IChildIParent.

注意 - 私有类是 C# 中的嵌套类。我不能告诉你这些类应该嵌套在哪个类中——这取决于你的项目。如果没有这样合理的地方,您可以创建一个子/父 DLL 库,并拥有internal实现公共接口的子类和父类。

顺便说一句,我不明白为什么你同时拥有ParentChild类,尤其是不明白为什么 Child 是从 Parent 派生的。如果你有一个Node类,你可以拥有一个Parent带有私有 setter 的属性,而不必担心。

于 2015-01-04T09:21:06.447 回答
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 刚刚进行了编辑以提出类似的建议。

于 2015-01-04T09:29:33.277 回答
1

如果您需要Parent并且Child是不同的班级,那么您可以使用事件来做到这一点。每当添加和删除a 时,使Parent该类提供一个事件,然后对此进行侦听并适当地设置其自己的父级。实际上,子列表中的子列表成为主要数据,父列表成为反向引用,如下所示:ChildChildParent

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

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

于 2015-01-04T09:41:28.777 回答