C# > IEnumerable<T>, IList<T> を自前で実装してみた

  • 1
    Like
  • 0
    Comment
More than 1 year has passed since last update.

IEnumerable、IListの実装方法

について近頃、考えています。IEnumerableは割と頻繁に書いてるのですが、IListのほうはコレクションを扱うクラスを作ってみたかったので、今回、IListを実装してみました。いや~、結構、ありますね。実装しなきゃならないメソッドやプロパティ。

サンプルの説明

それぞれのインターフェースを自分なりに実装してみました。効率とかあまり考えていません。とりあえず「動く」というのを目標にしていますが、如何でしょうか。何かつっこむところなどありましたら、教えて頂けると大変、助かります。

面白かった事

最後のコード
MyArray<int> array3 = new MyArray<int> { 1, 2, 3 };
で、MyArray<T>.Addメソッドが呼ばれるのが面白いと思いました。

Intelli Test

初めてIntelli TestというものでMyArrayをテストしてみたので、若干、例外処理が煩雑に入ってしまってます。他にスマートな書き方はあるんですかね? 例外処理を入れたので一応、全てのテストはグリーンになりましたが、プログレスが満タンにならないので、ガバレッジがうまくいってないような感じです。まあ、それは今回の件とは関係ありませんが。

ソースコード

Program.cs
using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApplication9
{
    public class Program
    {
        public static void Main()
        {
            MyArray<int> array = new MyArray<int>();

            for (int i = 0; i < 10; i++)
            {
                array.Add(i);
            }
            WriteArray("add", array);

            Write("Count", array.Count.ToString());
            Write("IsReadOnly", array.IsReadOnly);

            Console.Write("Indexer(get)    : ");
            for (int i = 0; i < array.Count; i++)
            {
                Console.Write($"{array[i]}");
            }
            Console.WriteLine("");

            array.RemoveAt(5);
            WriteArray("RemoveAt", array);

            array.Remove(3);
            WriteArray("Remove", array);

            array.Insert(3, 9);
            array.Insert(5, 9);
            WriteArray("Insert", array);

            array[3] = 3;
            array[5] = 5;
            WriteArray("indexer(set)", array);

            bool isSeven = array.Contains(7);
            Write("Contains", isSeven);

            int indexSeven = array.IndexOf(7);
            Write("IndexOf", indexSeven);

            int[] array2 = new int[20];
            array.CopyTo(array2, 2);
            WriteArray("CopyTo", array2);

            array.Clear();
            WriteArray("Clear", array);

            MyArray<int> array3 = new MyArray<int> { 1, 2, 3 };
            WriteArray("new { 1, 2, 3 }", array3);

            Console.WriteLine("\n\nPush any key!");
            Console.ReadKey();
        }

        static void WriteArray<T>(string text, T array)
            where T : IEnumerable
        {
            Console.Write($"{text, -15} : ");
            foreach (var item in array)
            {
                Console.Write($"{item}");
            }
            Console.WriteLine("");
        }

        static void Write<T>(string text, T item)
        {
            Console.WriteLine($"{text,-15} : {item.ToString()}");
        }
    }
}
MyArray.cs
using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApplication9
{
    public class MyArray<T> : IEnumerable<T>, IList<T>
    {
        public const int MAX_COUNT = 100;
        private T[] array = new T[0];

        public MyArray()
        {
        }

        public MyArray(int count)
        {
            if (MAX_COUNT < count)
            {
                throw new ArgumentException(nameof(MAX_COUNT) + " < " + nameof(count));
            }
            if (count < 0)
            {
                throw new ArgumentNullException(nameof(count) + " < 0");
            }
            array = new T[count];
        }

        public T this[int index]
        {
            get
            {
                if (array == null)
                {
                    throw new InvalidOperationException(nameof(array) + " == null");
                }
                if (index < 0 || array.Length <= index)
                {
                    throw new ArgumentException(nameof(index) + " < 0 || " + nameof(array) + ".Length <= " + nameof(index));
                }
                return array[index];
            }

            set
            {
                if (array == null)
                {
                    throw new InvalidOperationException(nameof(array) + " == null");
                }
                if (index < 0 || array.Length <= index)
                {
                    throw new ArgumentNullException(nameof(index) + " < 0 || " + nameof(array) + ".Length <= " + nameof(index));
                }
                array[index] = value;
            }
        }

        public int Count
        {
            get
            {
                if (array == null)
                {
                    throw new InvalidOperationException(nameof(array) + " == null");
                }
                return array.Length;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

        public void Add(T item)
        {
            if (array == null)
            {
                throw new InvalidOperationException(nameof(array) + " == null");
            }
            if (MAX_COUNT <= array.Length)
            {
                throw new ArgumentException(nameof(MAX_COUNT) + " <= " + nameof(array) + ".Length");
            }
            T[] temporary = new T[array.Length + 1];
            array.CopyTo(temporary, 0);
            temporary[temporary.Length - 1] = item;
            array = temporary;
        }

        public void Clear()
        {
            array = new T[0];
        }

        public bool Contains(T item)
        {
            if (array == null)
            {
                throw new InvalidOperationException(nameof(array) + " == null");
            }
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item) + " == null");
            }
            return Array.IndexOf(array, item) != -1;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            if (this.array == null)
            {
                throw new InvalidOperationException("this." + nameof(array) + " == null");
            }
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array) + " == null");
            }
            if(arrayIndex < 0 || array.Length <= arrayIndex)
            {
                throw new ArgumentException(nameof(arrayIndex) + " < 0 || " + nameof(array) + ".Length <= " + nameof(arrayIndex));
            }
            this.array.CopyTo(array, arrayIndex);
        }

        public IEnumerator<T> GetEnumerator()
        {
            foreach (var item in array)
            {
                yield return item;
            }
        }

        public int IndexOf(T item)
        {
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array) + " == null");
            }
            return Array.IndexOf(array, item);
        }

        public void Insert(int index, T item)
        {
            if (array == null)
            {
                throw new InvalidOperationException(nameof(array) + " == null");
            }
            if (index < 0 || array.Length <= index)
            {
                throw new ArgumentException(nameof(index) + " < 0 || " + nameof(array) + ".Length <= " + nameof(index));
            }
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item) + " == null");
            }
            if (MAX_COUNT <= array.Length + 1)
            {
                throw new ArgumentException(nameof(MAX_COUNT) + " <= " + nameof(array) + ".Length");
            }
            T[] temporary = new T[array.Length + 1];
            Array.Copy(array, 0, temporary, 0, index);
            Array.Copy(array, index, temporary, index + 1, array.Length - index);
            temporary[index] = item;
            array = temporary;
        }

        public bool Remove(T item)
        {
            if (array == null)
            {
                throw new InvalidOperationException(nameof(array) + " == null");
            }
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item) + " == null");
            }
            if(array.Length == 0)
            {
                throw new ArgumentNullException(nameof(array) + ".Length == 0");
            }
            int index = Array.BinarySearch(array, item);
            if (index < 0)
            {
                return false;
            }

            RemoveAt(index);

            return true;
        }

        public void RemoveAt(int index)
        {
            if (array == null)
            {
                throw new InvalidOperationException(nameof(array) + " == null");
            }
            if(index < 0 || array.Length <= index)
            {
                throw new ArgumentException(nameof(index) + " < 0 || " + nameof(array) + ".Length <= " + nameof(index));
            }
            T[] temporary = new T[array.Length - 1];
            Array.Copy(array, 0, temporary, 0, index);
            Array.Copy(array, index + 1, temporary, index, array.Length - index - 1);
            array = temporary;
        }

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

    }
}