如果我正确理解您的要求,您有一系列具有继承关系的类,并且您希望将它们排列在树结构中,其中每个实例都有相同类型的父级且仅具有相同类型。这是一个有趣的问题。
在考虑了一下这个之后,我建议你将需求分成两个平行但相关的对象图,这样你就有了
- 一组具有继承关系的类
- 一组类,可以包含第一组中的任何类,并且具有类型严格的父项和子项。
首先,让我们声明第一组相互继承的类。暂时忽略这Node
一点。
public class BaseClass
{
public Node ContainerNode { get; set; }
}
public class DerivedClass1 : BaseClass
{
}
public class DerivedClass2 : BaseClass
{
}
这些类不能做太多,但这只是一个例子。
现在让我们设置另一组可以参与树的类。树中的每个元素都称为 a Node
。
//Basic node
public class Node
{
}
//A node that can contain a T (which must be a BaseClass or derived from one)
public class Node<T> : Node where T : BaseClass
{
public T Parent { get; set; }
public T This { get; set; }
public Node(T innerClass)
{
this.This = innerClass;
innerClass.ContainerNode = this;
}
}
现在我们拥有了执行您所寻求的类型安全所需的一切。我们可以像这样在继承层次结构中创建类:
var child1 = new Node<DerivedClass1>(new DerivedClass1());
var parent1 = new Node<DerivedClass1>(new DerivedClass1());
child1.Parent = parent1.This;
让我们看看如果我们错误地混淆了 DerivedClass1 和 DerivedClass2 会发生什么:
var child2 = new Node<DerivedClass2>(new DerivedClass2());
var parent2 = new Node<DerivedClass1>(new DerivedClass1()); //Oops
child2.Parent = parent2.This; //Does not compile
如您所见,该Parent
属性现在是类型安全的。
现在所有的东西 ^^^^ 看起来有点乱,所以让我们通过添加一些辅助方法来清理它。
public class Node
{
public T GetParent<T>() where T : BaseClass
{
return ((Node<T>)this).Parent;
}
static public Node<T> Create<T>(T innerClass) where T : BaseClass
{
return new Node<T>(innerClass);
}
static public T GetParent<T>(T child) where T: BaseClass
{
return child.ContainerNode.GetParent<T>();
}
static public implicit operator T (Node<T> input)
{
return input.This;
}
}
现在,由于编译器可以推断<T>
参数,我们的声明更加简洁:
var child1 = Node.Create(new DerivedClass1());
var parent1 = Node.Create(new DerivedClass1());
child1.Parent = parent1;
任何派生类都很容易找到自己的父类:
public class DerivedClass1 : BaseClass
{
protected DerivedClass1 Parent
{
get
{
return Node.GetParent(this); //This is type safe!
}
}
}
反对所有这一切的一个理由是,您不希望编码人员处理这个 Node 层。好吧,他们没有,因为我们设置了一个隐式转换:
Node<DerivedClass1> a = Node.Create(new DerivedClass1());
DerivedClass1 b = a; //Works!!! And is type-safe.
DotNetFiddle 上的完整工作代码。