C#

C# コレクションクラスを自作してみる(2/2)

C# コレクションクラスを自作してみる(1/2)」で、今回作成する自作コレクションクラスに必要なものを準備しました。
(準備しないと、今回のコレクションクラスは動きません)

自作コレクションクラス本体を作成していきます。

 

コレクションクラスに必要な実装

前回も書きましたが、もう一度おさらい

  • int ICollection.Countプロパティ
  • object ICollection.SyncRootプロパティ
  • bool ICollection.IsSynchronizedプロパティ
  • void ICollection.CopyTo(Array list, int index)メソッド
  • IEnumerator IEnumerable.GetEnumerator()メソッド

それぞれ下記のようなものです。

 

int ICollection.Countプロパティ

このコレクションクラスで保有する要素の数を返すプロパティ

 

object ICollection.SyncRootプロパティ

アクセスを同期するために使用できるオブジェクトを返すプロパティ
このプロパティは常に現在のインスタンスを返します。

 

bool ICollection.IsSynchronizedプロパティ

アクセスが同期されている (スレッド セーフである) かどうかを示す値を返すプロパティ
アクセスが同期されている (スレッド セーフである) 場合は true。それ以外の場合は false。

 

void ICollection.CopyTo(Array list, int index)メソッド

要素を Array にコピーします。Array の特定のインデックス(‘index’)からコピーが開始されるように実装します。

 

IEnumerator IEnumerable.GetEnumerator()メソッド

コレクションを反復処理する列挙子を返します。

 

コレクションクラス本体の実装

説明文を見ていると実装がややこしそうに思えますが、実際の実装はあまり複雑ではありません。

上記のプロパティとメソッドをメインとして実装すると下記のようになります。

 

    /// <summary>
    /// コレクションクラス
    /// </summary>
    public class ItemObjectCollection : ICollection
    {
        /// <summary>
        /// 管理対象のオブジェクト
        /// </summary>
        private ArrayList _list = new ArrayList();

        /// <summary>
        /// ICollection.Countプロパティ
        /// </summary>
        int ICollection.Count
        {
            get
            {
                return _list.Count;
            }
        }

        /// <summary>
        /// ICollection.SyncRootプロパティ
        /// </summary>
        object ICollection.SyncRoot
        {
            get
            {
                return this;
            }
        }

        /// <summary>
        /// ICollection.IsSynchronizedプロパティ
        /// </summary>
        bool ICollection.IsSynchronized
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ItemObjectCollection()
        {
            // コンストラクタ
            this._list.Clear();
        }

        /// <summary>
        /// ICollection.CopyTo
        /// </summary>
        /// <param name="list">コピー先のリスト</param>
        /// <param name="index">開始インデックス</param>
        void ICollection.CopyTo(Array list, int index)
        {
            foreach(var obj in this._list)
            {
                list.SetValue(obj, index);
                index = index + 1;
            }
        }

        /// <summary>
        /// 列挙子取得処理
        /// </summary>
        /// <returns>当クラスオブジェクトの列挙子オブジェクト</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(_list);
        }
    }

 

インターフェースに必要なものだけ実装すると、ビルドは通るのですが、使えません。

それは、この状態ではコレクションクラスが管理する”データ本体”を扱えないからです。

管理する”データ本体”は、仕様や設計などで多様な実現方法があることもあり、ICollectionクラスには用意されていません。

管理する”データ本体”を扱うためのメソッド

このサンプルのコレクションクラスで管理する”データ本体”は「ArrayList _list」です。

このデータ本体にアクセスするためのメソッドして「追加(Add)」と「削除(Remove)」を追加します。

 

追加(Add)

        /// <summary>
        /// Addメソッド
        /// </summary>
        /// <param name="obj">追加対象のオブジェクト</param>
        public void Add(ItemObject obj)
        {
            this._list.Add(obj);
        }

 

削除(Remove)

        /// <summary>
        /// Removeメソッド
        /// </summary>
        /// <param name="index">削除対象のオブジェクト</param>
        public void Remove(int index)
        {
            if((index >= _list.Count) || (index < 0))
            {
                // インデックスが範囲外の場合
                throw new ArgumentOutOfRangeException(string.Format("インデックスが範囲外です(index={0})", index));
            }
            this._list.RemoveAt(index);
        }

 

削除のほうにはインデックスの範囲外チェックを入れています。

これで自作のコレクションクラスができました。

 

テストプログラムで動作チェック

ここでは、自作のコレクションクラスがforeachで反復処理されるかを見るだけとします。

 

        static void Main(string[] args)
        {
            ItemObjectCollection col = new ItemObjectCollection();

            col.Add(new ItemObject("Object001"));
            col.Add(new ItemObject("Object002"));
            col.Add(new ItemObject("Object003"));

            foreach(ItemObject obj in col)
            {
                Console.WriteLine(obj.Name);
            }
        }

 

 

 

タイトルとURLをコピーしました