3

タイトルの通りですが、可能かどうか知りたいです。

同じデータ構造内の別のノードを指すノード クラスがあります。

class DataStructure<T, N>
  where T : IComparable<T>
  where N : Node<T> {
    N RootNode;

    // More code to follow, etc.
}

class Node<T>
  where T : IComparable<T> {
    T value;
    Node<T> NextNode;

    Node<T> GetLastNode() {
        Node<T> current = this;
        while (this.NextNode != null) {
            current = current.NextNode;
        }
        return current;
    }

    // etc.
}

の特定の汎用バージョンに関する詳細情報を得るために、Node クラスを展開できるようにしたいと考えていますDataStructure。例えば:

class AdvancedNode<T> : Node<T>
  where T : IComparable<T> {
    int Height;
    int Size;
    // etc.
}

NextNodeこれに関する問題は、リンクをたどろうとするときです。

DataStructure<char, AdvancedNode<char>> d = new DataStructure<char, AdvancedNode<char>>();
d.RootNode = new AdvancedNode<char>();
d.RootNode.NextNode = new AdvancedNode<char>();
AdvancedNode<char> y = d.RootNode.NextNode;    // TYPE ERROR! Will not compile

さらに、次のようなことができないようにしたいと思います。

DataStructure<char, AdvancedNode<char>> d = new DataStructure<char, AdvancedNode<char>>();
d.RootNode = new AdvancedNode<char>();
d.RootNode.NextNode = new Node<char>();    // This will compile, 
                                           // but I don't want it to!

Node.NextNodeと同じタイプになるビルド時に強制する方法はありthisますか? キャストを行う必要なく、一般的なデータ構造を実装できるようにしたいと考えています。出来ますか?劣った設計パターンを使用していませんか?

4

4 に答える 4

2

機能するはずの1つの解決策は、「再帰ジェネリック」を使用することです(この投稿を参照)。

の定義Node<T>を実装する必要Node<N, T>がある場所に変更します...NNode<N, T>

abstract class Node<N, T>
    where N : Node<N, T>  // Here is the recursive definition
    where T : IComparable<T>
{
    T value;
    public N NextNode;

    public N GetLastNode()
    {
        N current = (N)this;
        while (this.NextNode != null)
        {
            current = current.NextNode;
        }
        return current;
    }

    // etc.
}

次に、 の基本クラスを に変更するだけAdvancedNode<T>ですNode<AdvancedNode<T>, T>

class AdvancedNode<T> : Node<AdvancedNode<T>, T>
    where T : IComparable<T>
{
    int Height;
    int Size;
    // etc.
}

toの型パラメーターNの制約と同様に。DataStructure<T, N>Node<N, T>

class DataStructure<T, N>
    where T : IComparable<T>
    where N : Node<N, T>
{
    public N RootNode;

    // More code to follow, etc.
}

残念ながら、「再帰ジェネリック」を使用してクラスを直接インスタンス化することはできませんNode<Node<Node<..., T>, T>, T>。正しいタイプが必要な場合は、次のように記述する必要があるためです。これが私が抽象化した理由です。単純なノードを作成するために、新しいタイプを作成しました。

class SimpleNode<T> : Node<SimpleNode<T>, T>
    where T : IComparable<T>
{
}
于 2013-07-25T22:44:50.460 に答える
1

私はVSを持っていませんが、私にはあなたがすべきように見えます:

  1. に変更Node<T>して、としてNode<TData,TNode>宣言します。NextNodeNode<TData,TNode>
  2. として宣言AdvancedNodeAdvancedNode<TData> : Node<TData,AdvancedNode<TData>>ます。

これにより、サブノードがルート ノードと同じタイプになります。他のすべてのノード タイプに対して 2) を繰り返します。

  1. RootNodeプロパティを移動しますNode(データよりも属していると思われる場所)。
  2. に変更DataStructure<T,N>しますDataStructure<TNode>(必要に応じて推測TDataTNodeます)

これにより、コードが (関心の分離という点で) よりクリーンになり、理解しやすくなり、DataStructure をノード タイプに依存させる必要がなくなり、単純化に役立ちます。2 つのジェネリック型を相互に依存させるのは良い設計とは思えないので、可能であればそれを排除することを目指します。

于 2013-07-25T22:47:11.900 に答える
0

代替案の 1 つは、継承の使用に反対する構成を指定することです。これの欠点は、特定の構成を拡張することがより困難になることです。

たとえば、質問のクラスを使用すると、次のようになります。

class DataStructure<T, D>
  where T : IComparable<T> {
    Node<T, D> RootNode;

    // More code to follow, etc.
}

class Node<T, D>
  where T : IComparable<T> {
    T value;
    D data;
    Node<T, D> NextNode;

    Node<T, D> GetLastNode() {
        Node<T, D> current = this;
        while (current .NextNode != null) {
            current = current.NextNode;
        }
        return current;
    }

    // etc.
}

class AdvancedNodeData {
    int Height;
    int Size;
    // etc.
}

DataStructure<char, AdvancedNodeData> d = new DataStructure<char, AdvancedNodeData>();
d.RootNode = new Node<char, AdvancedNodeData>();
d.RootNode.NextNode = new Node<char, AdvancedNodeData>();
Node<char, AdvancedNodeData> y = d.RootNode.NextNode;
于 2013-07-30T16:02:16.920 に答える