2009-07-13 20 views
1

親子階層クラスを実装する方法に関するまともな例を見つけることは難しいです。 ツリービューコントロールをクラス階層に変換し、各ノードに余分なデータを追加し、IEnumerableを使用して各親のノードをeasely繰り返し処理できるようにしました。親子クラス階層を実装する

public IEnumerable<Node> GetAllChildsFromParent(Node parent) 
{ 
    foreach (Node node in parent.NodeChildsCollection) 
    { 
     yield return node; 
    } 
} 

私はすでに次のコードを実装しているが、捕まってしまったと 本当にないが、私は正しい軌道に乗っていたか否かの手掛かりを持っていますか?これを完了するためにどのように進めるべきですか?

public class NodeChildsCollection : IEnumerable<Node> 
{ 
    IList<Node> nodeCollection = new List<Node>(); 
    Node parent; 

    public Node Parent 
    { 
     get { return parent; } 
     set { parent = value; } 
    } 

    public NodeChildsCollection() 
    { 
    } 


    public void AddNode(Node parent, Node child) 
    { 
     this.parent = parent; 
     nodeCollection.Add(child); 
    } 

    #region IEnumerable<Node> Members 

    public IEnumerator<Node> GetEnumerator() 
    { 
     foreach (Node node in nodeCollection) 
     { 
      yield return node; 
     } 
    } 

    #endregion 

    #region IEnumerable Members 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 
} 

public class Node 
{ 

    NodeChildsCollection nodeChildsCollection = new NodeChildsCollection(); 

    public Node Parent 
    { 
     get { return nodeChildsCollection.Parent; } 
     set { nodeChildsCollection.Parent = value; } 
    } 


    public void AddChild(Node child) 
    { 
     nodeChildsCollection.AddNode(this, child); 
    } 
} 

答えて

2

ノードの責任とコレクションの責任を混在させています。コレクションの親をどのように設定しているかを確認してください。親を持つコレクションではありません。そのノード。

私はこのようにように私のノードを構築したい:

public class Node 
{ 
    public Node Parent {get;set;} // null for roots 

    public NodeCollection Children {get; private set;} 

    public Node() 
    { 
    Children = new NodeCollection(); 
    Children.ChildAdded += ChildAdded; 
    Children.ChildRemoved += ChildRemoved; 
    }; 
    private void ChildAdded(object sender, NodeEvent args) 
    { 
    if(args.Child.Parent != null) 
     throw new ParentNotDeadYetAdoptionException("Child already has parent"); 
    args.Child.Parent = this; 
    } 
    private void ChildRemoved(object sender, NodeEvent args) 
    { 
    args.Child.Parent = null; 
    } 
} 

そしてNodeCollectionは

public class NodeCollection : INodeCollection {/*...*/} 

のようになりますとINodeCollectionは次のようになります。

public interface INodeColleciton : IList<Node> 
{ 
    event EventHandler<NodeEvent> ChildAdded; 
    event EventHandler<NodeEvent> ChildRemoved; 
} 

コレクションの責任がオンになっていますNodeの子コレクションプロパティもちろん、ノードにINodeCollectionを実装させることはできますが、それはプログラミングの趣味です。私は子供たちにパブリックプロパティ(そのフレームワークがどのようにデザインされているか)を持たせることを好む。

この実装では、 "GetChildren"メソッドを実装する必要はありません。公共の子供の財産はそれらをすべての人に提供します。

1

ツリー形式のデータ構造の概念を、格納されている特定のデータと区別したい場合は、一般的なものにして汎用のコンテナにします。

また、ツリーが単一のルートを持つ場合、ツリーノードはそれ自身がツリーノードの集合であるため、(任意のコレクションと同様に)項目を追加する方法はAddと呼びます。子コレクションを別のオブジェクトにすることは、しばしばツリーのコレクションを持つ場合にのみ意味をなさないでしょう。ツリービューのルートには、単一のルートのツリーノードではなく複数のノードが含まれているため、これはWindows UIのツリービューで発生します。しかし、XMLやHTML DOMのようなものでは、常に1つのルートが存在するので、もっと簡単なものが適切だと思います。

最後に、yield returnで、IEnumerableのものを実装する必要はありません。標準コンテナの実装に転送するだけです。

public class TreeNode<TValue> : IEnumerable<TreeNode<TValue>> 
{ 
    private List<TreeNode<TValue>> _children = new List<TreeNode<TValue>>(); 

    public TreeNode<TValue> Parent { get; private set; } 

    public void Add(TreeNode<TValue> child) 
    { 
     _children.Add(child); 
     child.Parent = this; 
    } 

    public void Remove(TreeNode<TValue> child) 
    { 
     _children.Remove(child); 
     child.Parent = null; 
    } 

    public IEnumerator<TreeNode<TValue>> GetEnumerator() 
    { 
     return _children.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return _children.GetEnumerator(); 
    }  
} 

実際にはあなたはそれがIList<TreeNode<TValue>>を実装し、子どもたちを追加/削除するたびにParent財産の適切な操作で、リストへのすべてのメソッドを転送作ることができます。

関連する問題