C# 泛型,其中 T class :(继承 class)

C# generic, where T class : (inheritance class)

我有两种类型的节点,一种是 MyLinkNode 用作基础,另一种是继承 MyLinkNode 的 GraphNode。

我尝试使用 MyLinkNode 创建 MyQueue。一切正常,直到我尝试将 GraphNode 添加到 MyQueue。我不能将 MyQueue 与 GraphNode 一起使用,因为它更大。

另一种方法是为 GraphNode 创建另一个队列,但这意味着如果我有更多类型的节点,我将需要创建很多 class。 有什么建议吗?

public class MyQueue<T> where T : MyLinkNode<T> 
{
    private T Head;
    private T Last;
    public MyQueue(){ ... }
    public void Enqueue(T item)
    {
        item.Prev = Last;
        Last.Next = item;
        Last = item;
    }
}
public class MyGraphQueue
{   
    //everything is the same with MyQueue besides the Node Type
    //I don't want to create like this.
    private GraphNode Head;
    private GraphNode Last;
    public MyGraphQueue(){ ... }
    public void Enqueue(GraphNode item)
    {
        item.Prev = Last;
        Last.Next = item;
        Last = item;
    }
}
public class MyLinkNode<T>
{
    public T data { get; set; }
    public MyLinkNode<T> Next { get; set; }
    public MyLinkNode<T> Prev { get; set; }
}
public class GraphNode<T> : MyLinkNode<T>
{
    public GraphNode()
    {
        this.adjacencyNodes = new List<GraphNode<T>>();
        this.isVisited = false;
    }

    public List<GraphNode<T>> adjacencyNodes;
    public bool isVisited { get; set; }
}
public void BFS<T>(GraphNode<T> v)
{
    MyQueue<GraphNode<T>> queue = new MyQueue<GraphNode<T>>(); // error, can't implicit convert GraphNode to MyLinkNode<T>
    MyGraphQueue queue = new MyGraphQueue(); //It's how I do now.

 }

这并不奇怪。你需要

public class MyQueue<T, S> where T : MyLinkNode<S>
{
    private T Head;
    private T Last;
    public MyQueue() {  }
    public void Enqueue(T item)
    {
        item.Prev = Last;
        Last.Next = item;
        Last = item;
    }
}

public void BFS(GraphNode v)
{
    MyQueue<GraphNode, string> queue = new MyQueue<GraphNode, string>(); 
}

MyQueue<T> where T : MyLinkNode<T> 无法接受 MyLinkNode<string>

因为这里 T 是字符串。但是,显然 string 没有继承自 MyLinkNode

我认为解决方案比您想象的要简单。

只需设置队列中值的类型(T),内部使用MyLinkNode<T>:

public class MyQueue<T> 
{
    private MyLinkNode<T> Head;
    private MyLinkNode<T> Last;

    public void Enqueue(MyLinkNode<T> item)
    {
        item.Prev = Last;
        Last.Next = item;
        Last = item;
    }
}

public void BFS(GraphNode v)
{
    MyQueue<string> queue = new MyQueue<string>(); // no error anymore
    queue.Enqueue(v);
}

问题出在你的第一行。

使用:

public class MyQueue<T> where T : MyLinkNode<string> { }

而不是:

public class MyQueue<T> where T  : MyLinkNode<T> { }

它会正常工作。

这是一个标准的泛型继承问题。您需要将 Queue 需要的内容与泛型类型分开。只需为队列约束添加另一个基础class。

这将使队列保证所有项目都具有类型 T,并且不需要额外的类型或所有具体类型的多个 class 定义。 Eric Lippert 有一篇很好的文章 here 关于为什么在泛型系统中需要此限制。

 public class CallingClass
{
    public void BFS(GraphNode v)
    {
        MyQueue<GraphNode> queue = new MyQueue<GraphNode>(); // error, can't implicit convert GraphNode to MyLinkNode<T>
       // MyGraphQueue queue = new MyGraphQueue(); //It's how I do now.

    }
}
public class QueueItem
{
    public QueueItem Next { get; set; }
    public QueueItem Prev { get; set; }
}

public class MyQueue<T> where T : QueueItem
{
    private T Head;
    private T Last;
    public MyQueue() {  }
    public void Enqueue(T item)
    {
        item.Prev = Last;
        Last.Next = item;
        Last = item;
    }
}

public class MyLinkNode<T>: QueueItem
{
    public T data { get; set; }

}
public class GraphNode : MyLinkNode<string>
{
    public GraphNode()
    {
        this.adjacencyNodes = new List<GraphNode>();
        this.isVisited = false;
    }

    public List<GraphNode> adjacencyNodes;
    public bool isVisited { get; set; }
}