当存在类层次结构并且子节点必须能够到达其父节点时,通常会出现此问题。
如果没有更多信息,很难说什么最适合您,但您有几个选择:
- 做你现在正在做的事情,即有一个字段保存对你的父节点的引用并手动跟踪这些引用。
- 有一个字段引用你的父节点并安排类,以便自动执行(这种方法在下面解释,尽管它有它的缺点)。
- 有一个单独的类,它将保留每个子节点到其父节点的映射并手动更新它(如果您想避免在子类中有额外的字段)。
- 有一个单独的类,它必须用于从父集合中添加或删除子节点并更新这些引用。这将要求所有插入和删除都通过此类完成,而不是直接使用
myVisualServers.Add
or添加它们myVisualServers.Remove
。
- 让这些方法的调用者将引用传递给父类(如@tamijud 建议的)。这并不能确保您将获得正确的父母,或者呼叫者将完全知道此信息。
- 最后,如果
myVisualServers
集合在类的实例化之后应该是不可变的VisualService
,那么它可能会简化事情,因为您可以在构造函数中传递整个集合并将所有引用连接到那里。
如果您想自动执行此分配,您可以创建自己的“智能”AbstractVisualServer
集合,该集合将在插入和删除项目时执行此操作。然而,这种方法的问题在于,您会被绑定到这个特定的实现,并且不能依赖其他接口来为您执行此操作(没有人保证不同的实现IVisualService
也会这样做)。
在这种情况下,我假设这是您想要实现的目标:
Parent parent = new Parent() { Name = "Parent" };
Child child = new Child() { Name = "Child" };
// starting conditions
Debug.Assert(parent.Children.Count == 0);
Debug.Assert(child.Parent == null);
// adding a child should set its parent
parent.Children.Add(child);
Debug.Assert(child.Parent == parent);
// removing a child should clear its parent
parent.Children.Remove(child);
Debug.Assert(child.Parent == null);
// setting a parent should add that child to the collection
child.Parent = parent;
Debug.Assert(parent.Children.Contains(child));
// clearing a parent should remove that child from the collection
child.Parent = null;
Debug.Assert(parent.Children.Count == 0);
首先,您需要创建一个自定义集合类,它将拦截Add
和Remove
方法:
public class Parent
{
public string Name { get; set; }
// Note that this is a custom private collection class
private readonly ChildCollection _children;
public ICollection<Child> Children
{
get { return _children; }
}
private class ChildCollection :
System.Collections.ObjectModel.Collection<Child>
{
private readonly Parent _parent;
public ChildCollection(Parent parent)
{
_parent = parent;
}
protected override void InsertItem(int index, Child item)
{
// remove from previous parent
if (item.Parent != null)
item.Parent.Children.Remove(item);
base.InsertItem(index, item);
// assign the new parent
item.Parent = _parent;
}
protected override void RemoveItem(int index)
{
// this item no longer has a parent
var item = this[index];
base.RemoveItem(index);
item.Parent = null;
}
protected override void SetItem(int index, Child item)
{
// remove from previous parent
if (item.Parent != null)
item.Parent.Children.Remove(item);
base.SetItem(index, item);
// assign the new parent
item.Parent = _parent;
}
protected override void ClearItems()
{
foreach (var i in this)
i.Parent = null;
base.ClearItems();
}
}
public Parent()
{
_children = new ChildCollection(this);
}
}
并且Child
班级也必须是“父母意识”的:
public class Child
{
public string Name { get; set; }
private Parent _parent;
public Parent Parent
{
get
{
return _parent;
}
set
{
if (_parent == value)
return;
if (_parent != null && _parent.Children.Contains(this))
_parent.Children.Remove(this);
_parent = value;
if (_parent != null && !_parent.Children.Contains(this))
_parent.Children.Add(this);
}
}
}