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