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,这将需要publicAdd(Child)
method当然,正如在评论和前面的回答中所述,您还需要封装将Child添加到父级,这将需要publicAdd(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中时,将类型约束放在父类上