2017-05-27 203 views
0

我有兩種類型的節點,一種是MyLinkNode它用作基礎,另一種是繼承MyLinkNode的GraphNode。C#泛型,其中T類:(繼承類)

我嘗試使用MyLinkNode創建MyQueue。一切都還好,直到我嘗試將GraphNode添加到MyQueue。由於GraphNode更大,我無法使用MyQueue。

另一種方法是爲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. 

} 
+0

我不明白你的意思「不能使用GraphNode的MyQueue,因爲它更大。」 –

+0

對於我的糟糕解釋感到抱歉。如果我用GraphNode使用MyQueue,編譯器會說它是非法的,因爲GraphNode不能隱式轉換爲MyLinkNode。 –

回答

0

這是一個標準的泛型繼承問題。您需要將隊列需要與泛型類型分開。只需爲隊列約束添加另一個基類即可。

這將使隊列保證所有具有類型T的項目,並且不需要額外的類型或多個具體類型的定義。關於泛型系統需要此限制的原因,Eric Lipert有一篇很好的文章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; } 
} 
+1

謝謝,你有我的觀點,一個優雅的用途。再次感謝。 –

0

這並不奇怪。您需要

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

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

問題是從你的第一行的到來。

用途:

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

相反的:

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

,它會正常工作。