ツリー構造クラスの自作

C#ではList, ObservableCollectionなど便利なクラスが標準で提供されていますが、ツリー構造はありません。

親切な方が以下のツリーコレクションを用意していたので、ダウンロードして使ってみたところ、かなり高機能なのですが継承して使用するにはasでキャストしたりして面倒で、やっぱり自分で実装した方が良いということで、必要最小限のツリー構造クラスを作成してみました。コメントはVisual Studioの記法です。

http://www.codeproject.com/Articles/12476/A-Generic-Tree-Collection

まずはインターフェースITreeNode.cs(ITreeNode)

/// <summary>
/// ツリー構造のインターフェース
/// </summary>
public interface ITreeNode<T>
{
    T Parent { get; set; }
    IList<T> Children { get; set; }

    T AddChild(T child);
    T RemoveChild(T child);
    bool TryRemoveChild(T child);
    T ClearChildren();
    bool TryRemoveOwn();
    T RemoveOwn();
}

その実装クラスTreeNodeBase.cs(TreeNodeBase)

/// <summary>
/// 簡易ツリー構造のジェネリッククラス
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class TreeNodeBase<T> : ITreeNode<TreeNodeBase<T>>  where T : class
{
    /// <summary>
    /// 親への参照フィールド
    /// </summary>
    protected TreeNodeBase<T> parent = null;

    /// <summary>
    /// 親への参照プロパティ
    /// </summary>
    public virtual TreeNodeBase<T> Parent
    {
        get
        {
            return parent;
        }
        set
        {
            parent = value;
        }
    }

    /// <summary>
    /// 子ノードのリストフィールド
    /// </summary>
    protected IList<TreeNodeBase<T>> children = null;

    /// <summary>
    /// 子ノードのリストプロパティ
    /// </summary>
    public virtual IList<TreeNodeBase<T>> Children
    {
        get
        {
            if (children == null)
                children = new List<TreeNodeBase<T>>();
            return children;
        }
        set
        {
            children = value;
        }
    }

    /// <summary>
    /// 子ノードを追加する。
    /// </summary>
    /// <param name="child">追加したいノード</param>
    /// <returns>追加後のオブジェクト</returns>
    public virtual TreeNodeBase<T> AddChild(TreeNodeBase<T> child)
    {
        if (child == null)
            throw new ArgumentNullException("Adding tree child is null.");

        this.Children.Add(child);
        child.Parent = this;

        return this;
    }

    /// <summary>
    /// 子ノードを削除する。
    /// </summary>
    /// <param name="child">削除したいノード</param>
    /// <returns>削除後のオブジェクト</returns>
    public virtual TreeNodeBase<T> RemoveChild(TreeNodeBase<T> child)
    {
        this.Children.Remove(child);
        return this;
    }

    /// <summary>
    /// 子ノードを削除する。
    /// </summary>
    /// <param name="child">削除したいノード</param>
    /// <returns>削除の可否</returns>
    public virtual bool TryRemoveChild(TreeNodeBase<T> child)
    {
        return this.Children.Remove(child);
    }

    /// <summary>
    /// 子ノードを全て削除する。
    /// </summary>
    /// <returns>子ノードを全削除後のオブジェクト</returns>
    public virtual TreeNodeBase<T> ClearChildren()
    {
        this.Children.Clear();
        return this;
    }

    /// <summary>
    /// 自身のノードを親ツリーから削除する。
    /// </summary>
    /// <returns>親のオブジェクト</returns>
    public virtual TreeNodeBase<T> RemoveOwn()
    {
        TreeNodeBase<T> parent = this.Parent;
        parent.RemoveChild(this);
        return parent;
    }

    /// <summary>
    /// 自身のノードを親ツリーから削除する。
    /// </summary>
    /// <returns>削除の可否</returns>
    public virtual bool TryRemoveOwn()
    {
        TreeNodeBase<T> parent = this.Parent;
        return parent.TryRemoveChild(this);
    }

}

通知型のツリー構造を作成する場合は

Observableなクラスを作成したい場合は、このクラスを継承してプロパティをoverrideするか、直接ITreeNodeを継承して作ってもいいです。

注意はコレクションプロパティの継承で、子ノードを格納するChildrenはObservableCollectionで宣言することが出来ないので、定義する際に自分でListかどちらかをnewして代入して使用することになります。