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; }
}
我有两种类型的节点,一种是 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; }
}