泛型子C#的通用父级

时间:2011-03-09 19:19:13

标签: c# design-patterns generics

我有一个可以包含任何类型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对象?

4 个答案:

答案 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>
{
}
相关问题