3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-06

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();
        }

    }
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?