IEnumerableインターフェイス継承クラスの自作

ListとIEnumerableの違い

static List<int> getList1()
{
 var ary = Enumerable.Range(start: 1, count: 10);
 var list = new List<int>();
 list.AddRange(ary);
 
 return list;
}

static IEnumerable<int> getList2()
{
 var ary = Enumerable.Range(start: 1, count: 10);
 var list = new List<int>();
 list.AddRange(ary);

 return list;
}

static IEnumerable<int> getList3()
{
 foreach (var elm in Enumerable.Range(start: 1, count: 10))
 {
  yield return elm;
 }
}

static void Main(string[] args)
{

 var list1 = getList1();
 List<int> = ~ と同じ
 list1.ForEach(x => Console.WriteLine(x));
 1 2 3 4 5 6 7 8 9 10
 
 var list2 = getList2();
 IEnumerable<int> = ~ と同じ
 list2.ToList().ForEach(x => Console.WriteLine(x));
 1 2 3 4 5 6 7 8 9 10
 
 var list3 = getList3();
 IEnumerable<int> = ~ と同じ
 list3.ToList().ForEach(x => Console.WriteLine(x));
 1 2 3 4 5 6 7 8 9 10
}

IEnumerable<T>型変数は「列挙オブジェクト」と呼ばれるクエリ式へのポインタ
それ自体はデータを持たず遅延実行されるのでメモリの節約になる。
容量を気にしなくて良い、複数回参照する場合は配列、リストの方が優れている

IEnumerable

foreach処理を可能にするインターフェイス
var i = Enumerable.Range(~).Where(~);
IEnumerable i = ~ と同じ

//標準Listクラス
List<int> myList = new List<int>() { 0,1,2,3,4,5 };
//foreach処理が可能
foreach(var i in myList)
{
  Console.WriteLine(i);
  //⇒ 0 1 2 3 4 5
}

↑ を自分で実装する。
using System.Collections;

public class MyCollection : IEnumerable
{
  int[] _hoge;
  public MyCollection()
  {
    _hoge = new int[] { 0,1,2,3,4 };
  }
  
  //IEnumerableインターフェイスの継承により、↓GetEnumerator()メソッドの実装が強制される
  public IEnumerator GetEnumerator()
  {
    for (var i = 0; i < _hoge.Length; i++)
    {
      //yield:foreach処理で扱える形で返す
      yield return _hoge[i];
    }
  }
}

private void Form1_Load(object sender, EventArgs e)
{
  MyCollection myCollection = new MyCollection();
  //foreach処理が可能になっている。
  foreach(var i in myCollection)
  {
    Console.WriteLine(i);
    // ⇒ 0 1 2 3 4
  }
}

Imports System.Collections

Public Class MyCollection
  Implements IEnumerable
  
  Dim _hoge() As Integer
  
  Public Sub New()
    _hoge = { 0, 1, 2, 3, 4 }
  End Sub
  
  Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
    ‘ 配列をIEnumerable型へ変換
    Dim enumerable As IEnumerable(Of Integer) = _hoge
    Return enumerable.GetEnumerator
  End Function
End Class

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
  Dim myCollection As New MyCollection()
  
  For Each elm In myCollection
    Console.WriteLine(elm)
    ’ ⇒ 0 1 2 3 4
  Next elm
End Sub

IEnumerable<T>

・IEnumerableのジェネリック版(IEnumerableを継承している)
 ※「プログラム言語 ジェネリック」参照
・LINQの使用が可能

public class MyCollection<T> : IEnumerable<T>
{
  List<T> _hoge;
  public MyCollection()
  {
    _hoge = new List<T>();
  }
  
  public void Add(T item)
  {
    _hoge.Add(item);
  }
  
  public IEnumerator<T> GetEnumerator()
  {
    for (var i = 0; i < _hoge.Count; i++ )
    {
      yield return _hoge[i];
    }
  }
  
  // IEnumerableの継承による実装?
  // Public修飾不可、IEnumerableの省略不可
  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }
}

public void Form1_Load(object sender, EventArgs e)
{
  MyCollection<int> collection = new MyCollection<int>() { 0,1,2,3,4,5 };
  // T : int としてインスタンスを作成。Add()を実行。
  
  foreach (var i in collection)
  {
    Console.WriteLine(i);
    // ⇒ 0 1 2 3 4 5
  }
  
  // IEnumerable<T>の場合、LINQが使用可能
  List<int> myLINQ = collection.OrderByDescending(a => a).ToList();
  foreach (var i in myLINQ)
  {
    Console.WriteLine(i);
    // ⇒ 5 4 3 2 1 0
  }
}