【问题标题】:C# generic, where T class : (inheritance class)C# 泛型,其中 T 类:(继承类)
【发布时间】:2017-05-27 14:31:29
【问题描述】:

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

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

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

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.

 }

【问题讨论】:

  • 我不明白您所说的“不能将 MyQueue 与 GraphNode 一起使用,因为它更大。”
  • 对不起,我的解释很糟糕。如果我将 MyQueue 与 GraphNode 一起使用,编译器会说这是非法的,因为 GraphNode 不能隐式转换为 MyLinkNode。

标签: c# inheritance data-structures generic-list


【解决方案1】:

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

这将使队列保证所有具有类型 T 的项目,并且不需要所有具体类型的额外类型或多个类定义。 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; }
}

【讨论】:

    【解决方案2】:

    MyQueue&lt;T&gt; where T : MyLinkNode&lt;T&gt; 不能接受 MyLinkNode&lt;string&gt;

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

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

    只需设置队列中值的类型(T),里面使用MyLinkNode&lt;T&gt;

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

    【讨论】:

      【解决方案3】:

      这并不奇怪。你需要

      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>(); 
      }
      

      【讨论】:

        【解决方案4】:

        问题出在你的第一行。

        用途:

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

        代替:

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

        它会正常工作的。

        【讨论】:

          猜你喜欢
          • 2011-08-13
          • 1970-01-01
          • 2015-11-18
          • 2011-08-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多