[英]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.