簡體   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