2017-05-27 14 views
0

私は2つのタイプのノードを持っています.1つはMyLinkNodeです。これはベースとして使用され、もう1つはMyLinkNodeを継承するGraphNodeです。C#generic、ここで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

これは、Generics継承の標準的な問題です。キューがジェネリック型から必要とするものを分離する必要があります。キュー制約に別の基本クラスを追加するだけです。

これは、キューがタイプ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

これは驚くことではありません。あなたはTは文字列で、ここでMyLinkNode<string>

Beacuseを受け入れることはできません

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>を必要としています。しかし、明らかに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> { } 

、それが正常に動作します。