我有一个可以包含任何类型Node的父类Container,其中Node是父类特有的泛型类的子类,如下所示:
public class ContainerBase<NodeType, ObjectType>
where NodeType : NodeBase<ObjectType> where ObjectType : ObjectBase {
}
public abstract class NodeBase<T> where T : ObjectBase {
ContainerBase<NodeBase<T>, T> container;
public NodeBase(ContainerBase<NodeBase<T>, T> owner) {
container = owner;
}
}
我想要做的是创建具体的子类,以简化实现标准对象类型:
public class ContainerNormal : ContainerBase<NodeNormal, ObjectNormal> {
}
public class NodeNormal : NodeBase<ObjectNormal> {
//This doesn't work
public NodeNormal(ContainerNormal owner) : base(owner) { }
}
我有点理解为什么对基础构造函数的调用不起作用。它试图将ContainerNormal
转换为ContainerBase<NodeBase<ObjectNormal>, ObjectNormal>
,但这并不真正有效。
那么我错过了哪些设计模式才能使这项工作正常进行?或者我只需要在构造函数中加入ContainerBase<NodeBase<ObjectNormal>,ObjectNormal>
,即使它可能不一定是ContainerNormal
对象?
答案 0 :(得分:3)
探索:Covariance and contravariance,但这应该有效:
public class Container<TNode, T> where TNode : Node<T> { }
public abstract class Node<T>
{
Container<Node<T>, T> container;
public Node(Container<Node<T>, T> owner)
{
this.container = owner;
}
}
public class ContainerNormal<T> : Container<Node<T>, T> { }
public class NodeNormal<T> : Node<T>
{
public NodeNormal(ContainerNormal<T> container)
: base(container)
{
}
}
public class ContainerNormal : ContainerNormal<string> { }
public class NodeNormal : NodeNormal<string>
{
public NodeNormal(ContainerNormal container)
: base(container)
{
}
}
答案 1 :(得分:1)
在C#4中,您可以使用通用接口协方差实现此目的:
public class ContainerBase<NodeType, ObjectType> : IContainerBase<NodeType, ObjectType>
where NodeType : NodeBase<ObjectType> where ObjectType : ObjectBase {
}
public abstract class NodeBase<T> where T : ObjectBase {
IContainerBase<NodeBase<T>, T> container;
public NodeBase(IContainerBase<NodeBase<T>, T> owner) {
container = owner;
}
}
public class ContainerNormal : ContainerBase<NodeNormal, ObjectNormal> {
}
public interface IContainerBase<out NodeType, ObjectType>
where NodeType : NodeBase<ObjectType> where ObjectType : ObjectBase {
}
public class NodeNormal : NodeBase<ObjectNormal> {
//This doesn't work
public NodeNormal(ContainerNormal owner) : base(owner) { }
}
public class ObjectNormal : ObjectBase {}
public class ObjectBase{}
当然,只有当您的IContainerBase接口可以避免使用任何以NodeType
为输入的函数时,这才有效。例如,这将起作用:
public interface IContainerBase<out NodeType, ObjectType>
where NodeType : NodeBase<ObjectType> where ObjectType : ObjectBase
{
NodeType NodeTypeProp {get;}
}
......但这不会:
public interface IContainerBase<out NodeType, ObjectType>
where NodeType : NodeBase<ObjectType> where ObjectType : ObjectBase
{
NodeType NodeTypeProp {get;set;} // "set" not allowed on "out" type
}
还有一点需要注意:您注意到我必须将属性命名为“NodeTypeProp”而不是“NodeType”?那是因为我们没有遵循C#命名约定。您应该使用“T”前缀泛型类型名称:
public interface IContainerBase<out TNodeType, TObjectType>
where TNodeType : NodeBase<TObjectType> where TObjectType : ObjectBase
答案 2 :(得分:1)
你认为有一个技巧可以让你得到你想要的东西。您可以为NodeBase提供一个必须从NodeBase继承的附加泛型参数。这给出了一个看似递归的类型定义,但编译器有一种方法可以解决它。这样的事情应该有效:
public class NodeBase<T, TNode> :
where T : ObjectBase
where TNode : NodeBase<T, TNode>
{
private ContainerBase<TNode, T> container;
protected NodeBase(ContainerBase<TNode, T> owner)
{ container = owner; }
}
public class ContainerBase<NodeType, ObjectType> :
where NodeType : NodeBase<ObjectType, NodeType>
where ObjectType : ObjectBase
{
public NodeType GetItem() { ... }
}
public class NodeNormal : NodeBase<ObjectNormal, NodeNormal>
{
public NodeNormal(ContainerNormal owner) :
base(owner) { }
}
public class ContainerNormal :
ContainerBase<NodeNormal, ObjectNormal>
{
//GetItem would return NodeNormal here
}
答案 3 :(得分:0)
您可以按如下方式更改Container normal的定义:
public class ContainerNormal : ContainerBase<NodeBase<ObjectNormal>, ObjectNormal>
{
}