假设我有一个抽象基类,我想声明成员,它将匹配从这个基类派生的类的类型。
public abstract class BaseClass
{
protected BaseClass parent;
}
public class DerivedClass1 : BaseClass
{
// parent could be of type DerivedClass2
}
public class DerivedClass2 : BaseClass
{
// parent could be of type DerivedClass1
}
这不起作用,因为每个派生类中的parent
字段可以是从BaseClass
派生的任何内容。我想确保parent
中的DerivedClass1
字段只能是DerivedClass1
类型。所以我想也许我应该使用泛型。
public abstract class BaseClass<T> where T : BaseClass<T>
{
protected T parent;
}
这可能看起来令人困惑和循环,但它确实编译。它基本上是说parent
属于T
类型,必须从通用BaseClass
派生。所以现在派生类看起来像这样:
public class DerivedClass : BaseClass<DerivedClass>
{
// parent is of type DerivedClass
}
问题在于,当我声明DerivedClass
时,我必须自己强制执行类型匹配。没有什么可以阻止某人做这样的事情:
public class DerivedClass1 : BaseClass<DerivedClass2>
{
// parent is of type DerivedClass2
}
C#是否有办法这样做,以便在基类中声明的成员类型肯定与派生类型匹配?
我认为这类似于这个C ++问题试图提出的问题:Abstract base class for derived classes with functions that have a return type of the derived class
答案 0 :(得分:1)
如果我正确理解了您的要求,那么您将拥有一系列具有继承关系的类,并且您希望将它们排列在树结构中,其中每个实例都具有相同类型且具有相同类型的父类。这是一个有趣的问题。
稍微涂抹一下之后,我可以建议你将需求分成两个平行但相关的对象图,这样就可以了
首先,让我们声明第一组彼此继承的类。暂时忽略Node
位。
public class BaseClass
{
public Node ContainerNode { get; set; }
}
public class DerivedClass1 : BaseClass
{
}
public class DerivedClass2 : BaseClass
{
}
这些课程做得不多,但它只是一个例子。
现在让我们设置另一组可以参与树的类。树中的每个元素称为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<DerivedClass1> a = Node.Create(new DerivedClass1());
DerivedClass1 b = a; //Works!!! And is type-safe.