繁体   English   中英

泛型子C#的通用父级

[英]Generic parent of generic child C#

我有一个父类Container可能包含任何类型的Node,其中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转换为ContainerNormal ContainerBase<NodeBase<ObjectNormal>, ObjectNormal> ,它实际上不起作用。

那么我错过了哪些设计模式才能使这项工作正常进行? 或者我只需要在构造函数中接受ContainerBase<NodeBase<ObjectNormal>,ObjectNormal> ,即使它可能不一定是ContainerNormal对象?

探索: 协方差和逆变 ,但这应该工作:

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)
    {
    }
}

在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 

你认为有一个技巧可以让你得到你想要的东西。 您可以为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
}

您可以更改Container normal的定义,如下所示:

public class ContainerNormal : ContainerBase<NodeBase<ObjectNormal>, ObjectNormal>
{
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM