C# 编写封装的父/子数据结构的更简单方法?

C# 编写封装的父/子数据结构的更简单方法?,c#,hierarchy,encapsulation,friend,member-access,C#,Hierarchy,Encapsulation,Friend,Member Access,我发现自己经常编写“家长”和“孩子”的数据结构,其中: 父级具有对0到N个不同子级的引用 子项引用了0个父项或1个父项 引用必须是相互的。对于任何给定的父级,它引用的任何子级也必须引用给定的父级。对于任何给定的子级,它引用的父级必须引用回给定的子级 除了使用反射之外,不可能通过使用从两个类声明(non-private)外部访问的成员来违反上述规则 在实现类似的内容之前,可能采取的心理步骤可能从以下内容开始: public class Parent { private readonly

我发现自己经常编写“家长”和“孩子”的数据结构,其中:

  • 父级具有对0到N个不同子级的引用
  • 子项引用了0个父项或1个父项
  • 引用必须是相互的。对于任何给定的父级,它引用的任何子级也必须引用给定的父级。对于任何给定的子级,它引用的父级必须引用回给定的子级
  • 除了使用反射之外,不可能通过使用从两个类声明(non-
    private
    )外部访问的成员来违反上述规则
在实现类似的内容之前,可能采取的心理步骤可能从以下内容开始:

public class Parent
{
    private readonly List<Child> _children = new List<Child>();

    public readonly ReadOnlyCollection<Child> Children = _children.AsReadOnly();
}

public class Child
{
    private Parent _parent;

    public Parent Parent
    {
        get
        {
            return _parent;
        }
        set
        {
            if(value == _parent)
                return;

            if(_parent != null)
            {
                _parent._children.Remove(this);
                _parent = null;
            }

            if(value != null)
            {
                value._children.Add(this);
                _parent = value;
            }
        }
    }
}
public class SomeBigOuterClass {
    private interface IChildFriend {
        void SetParent(Parent parent);
    }

    public class Parent {
    }

    public class Child : IChildFriend {
        void IChildFriend.SetParent(Parent parent) {
            this.parent = parent;
        }
        private Parent parent;
    }
}
我要问的问题是,是否有其他方法可以实现相同的目标,而这些目标的缺点比这种方法少或少?我发现这种方法的主要缺点是:

  • 这可能导致大型脚本,尽管使用
    partial
    会有所帮助
  • 这可能会导致嵌套深度超过预期
  • 这可能导致详细的类名。要访问
    父项
    之外的
    子项
    ,必须使用
    父项.Child
    。在类名很长的情况下,尤其是使用泛型时,这可能会导致非常难看的代码
  • 泛型的使用(例如,实现编译时类型安全)可能会变得混乱。这似乎至少部分源于这样一个事实,
    Child
    是嵌套的,
    Parent.Child
    是与
    Parent.Child
    不同的类型,当您希望类型安全是相互的时,这可能会导致泛型的使用非常糟糕,或者需要退回到使用运行时强制的类型安全(尽管它通常可以被封装掉,例如,使用非通用的抽象基,其中
    公共
    访问器受
    保护

另一方面,这可能是一个很好的例子,说明使用
friend
扩展访问权限可以简化这些问题!

如我在评论中所述,在父级中添加一个Remove方法,至少不会公开整个子级列表。类似于:

public class Parent
    {
        private readonly List<Child> _children = new List<Child>();

        public readonly ReadOnlyCollection<Child> Children = _children.AsReadOnly();

        public void Remove(Child child)
        {
            if(child !=null) 
            {
             _children.Remove(child);
            }
        }
    }
公共类父类
{
私有只读列表_children=new List();
public readonly readonly collection Children=_Children.AsReadOnly();
公共无效删除(子项)
{
if(child!=null)
{
_儿童。移除(儿童);
}
}
}

如我在评论中所述,在父级中添加一个Remove方法,该方法至少不会公开整个子级列表。类似于:

public class Parent
    {
        private readonly List<Child> _children = new List<Child>();

        public readonly ReadOnlyCollection<Child> Children = _children.AsReadOnly();

        public void Remove(Child child)
        {
            if(child !=null) 
            {
             _children.Remove(child);
            }
        }
    }
公共类父类
{
私有只读列表_children=new List();
public readonly readonly collection Children=_Children.AsReadOnly();
公共无效删除(子项)
{
if(child!=null)
{
_儿童。移除(儿童);
}
}
}

当然,正如在评论和前面的回答中所述,您还需要封装向父级添加Child,这将需要public
Add(Child)
method

当然,正如在评论和前面的回答中所述,您还需要封装将Child添加到父级,这将需要public
Add(Child)
method

我喜欢使用公共的私有接口来公开如下属性:

public class Parent
{
    private readonly List<Child> _children = new List<Child>();

    public readonly ReadOnlyCollection<Child> Children = _children.AsReadOnly();
}

public class Child
{
    private Parent _parent;

    public Parent Parent
    {
        get
        {
            return _parent;
        }
        set
        {
            if(value == _parent)
                return;

            if(_parent != null)
            {
                _parent._children.Remove(this);
                _parent = null;
            }

            if(value != null)
            {
                value._children.Add(this);
                _parent = value;
            }
        }
    }
}
public class SomeBigOuterClass {
    private interface IChildFriend {
        void SetParent(Parent parent);
    }

    public class Parent {
    }

    public class Child : IChildFriend {
        void IChildFriend.SetParent(Parent parent) {
            this.parent = parent;
        }
        private Parent parent;
    }
}

我喜欢使用公共的私有接口来公开如下属性:

public class Parent
{
    private readonly List<Child> _children = new List<Child>();

    public readonly ReadOnlyCollection<Child> Children = _children.AsReadOnly();
}

public class Child
{
    private Parent _parent;

    public Parent Parent
    {
        get
        {
            return _parent;
        }
        set
        {
            if(value == _parent)
                return;

            if(_parent != null)
            {
                _parent._children.Remove(this);
                _parent = null;
            }

            if(value != null)
            {
                value._children.Add(this);
                _parent = value;
            }
        }
    }
}
public class SomeBigOuterClass {
    private interface IChildFriend {
        void SetParent(Parent parent);
    }

    public class Parent {
    }

    public class Child : IChildFriend {
        void IChildFriend.SetParent(Parent parent) {
            this.parent = parent;
        }
        private Parent parent;
    }
}

如何在父移除(子)中添加一个公共方法,该方法将从列表中移除子对象,但在父移除(子)中添加一个公共方法如何这将从列表中删除子级,但在父级内部这将允许打破相互引用的要求。可以删除子级,但子级仍将引用父级。我认为子级和父级都可以有添加/删除方法,根据首先调用的方法有条件地相互调用(可通过检查父项或子项参考来确定)虽然我可以看到,它很难跟随,并且有无穷的递归。它不会是无限的递归,如果它不是空的,你就会删除它。所以移除父函数,意味着如果它不是空的,如果它是空的,你就不会做它。所以没有无限的递归。我确信它是可行的,但是当你认为单个事务可以拥有时,它就有点可疑。涉及三个实体(两个父实体和一个子实体)。这将允许一个实体打破相互引用的要求。一个实体可以删除一个子实体,但子实体仍会引用父实体。我认为子实体和父实体都可以有添加/删除方法,根据第一个实体被调用的方法有条件地相互调用(可通过检查父项或子项参考来确定)虽然我可以看到,它很难跟随,并且有无穷的递归。它不会是无限的递归,如果它不是空的,你就会删除它。所以移除父函数,意味着如果它不是空的,如果它是空的,你就不会做它。所以没有无限的递归。我确信它是可行的,但是当你认为单个事务可以拥有时,它就有点可疑。涉及三个实体(两个父实体和一个子实体)。有趣的是,我从未考虑过以这种方式使用接口。请注意,仍然使用嵌套,但随着类与泛型和继承的关系变得更加复杂,它可能更易于管理。这是我带来“朋友”的方式回到C#,正如你可以从我的命名约定中看到的……该死,现在我觉得我必须重构我使用旧模式的代码:(我不得不说,当与泛型一起使用时,这种技术实际上在管理类型复杂性方面做得相当好。当子类嵌套在h中时,将类型约束放在父类上