(1) C#のIEnumerableとは?使い方(foreachでの要素取り出し)を順を追って解説
(1-1) IEnumerableとは?
(1-2) IEnumerableの実装の流れ
(1-2-1) STEP1:IEnumerableインターフェイスの実装
(1-2-2) STEP2:IEnumeratorインターフェイスの実装
(1-3) サンプルプログラムで理解を深める
(1) C#のIEnumerableとは?使い方(foreachでの要素取り出し)を順を追って解説
(1-1) IEnumerableとは?
C#のインターフェイスでカスタム配列への対話的なアクセス(foreachによるアクセス)を可能にします。
■IEnumerableの概要
IEnumerableインターフェイスは抽象メソッドGetEnumerator()メソッドのみを持つインターフェイスで、戻り値は「IEnumerator」インターフェイスを返却します。この「IEnumerator」インターフェイスを使うとカスタム配列の要素に対して、繰り返し処理でアクセスできる様になります。
(図111)

■IEnumeratorで出来る事・出来ない事
IEnumeratorインターフェイスは3つメソッドMoveNext()とReset()とCurrentがあります。「IEnumerable」を実装すると、foreachでループして要素を取得できるようになります。注意点として「IEnumerator」インターフェイスは要素に対してアクセスはできますが、変更する事はできません。
■IEnumeratorで配列にアクセスする際のお作法
通常、配列の要素にアクセスする際は「インデックス」を使いまが、IEnumeratorではインデックスの代わりに3つの抽象メソッド「Reset()」と「MoveNext()」と「Current()」を使って要素にアクセスします。
(1-2) IEnumerableの実装の流れ
ここからはIEnumerableの実装の流れ
(1-2-1) STEP1:IEnumerableインターフェイスの実装
まずは最初に「IEnumerable」インターフェイスを実装します。このインターフェイスには「GetEnumerator()」メソッドがあり、我々のカスタムクラスのアクセスに使う「IEnumerator」のオブジェクトを返却します。
(例)GetEnumeratorメソッドの実装
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
(1-2-2) STEP2:IEnumeratorインターフェイスの実装
次に「IEnumerator」インターフェイスを実装します。このインターフェイスは下記3つのメソッドがあり、これらの3つのメソッドを実装するとforeachによるループが可能となります。
// IEnumeratorインターフェイスのメソッドシグニチャ void Reset() bool MoveNext() object Current
①void Reset()メソッド
まずはReset()メソッドの実装です。Reset()メソッドはポインタ(現在の要素を指す変数)を開始地点にセットします(最初の要素の前に0番目の空要素があるイメージ)。ですので、インデックスとしては「-1」を割り当てています。
(例)Reset()メソッドの実装
public void Reset()
{
[現在位置変数名] = -1;
}
②bool MoveNext()メソッド
MoveNext()は次の要素に移動するためのメソッドです。内部的には現在位置(カレントポジション)の次の要素があるならばtrueを返却し、次の要素が無い場合はfalseを返却します。
(例)MoveNext()メソッドの実装
public bool MoveNext()
{
if ([現在位置変数名] < [配列名].Count - 1)
{
++[現在位置変数名];
return true;
}
return false;
}
③object Current()メソッド
特定の位置にある要素を返却するために使います。実際に要素を順番に取り出していく際は「MoveNext ()」と「Current」を組み合わせて使っていく形になります。
(例)Current()メソッドの実装
public object Current
{
get
{
return PersonList[CurrPosition];
}
}
(1-3) サンプルプログラムで理解を深める
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IEnumeratorTest
{
//①個人を管理するPersonクラス
class Person
{
private string FirstName;
private string LastName;
private int Age;
public Person(string firstName, string lastName, int age)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
}
public override string ToString()
{
return "Name:" + FirstName + " " + LastName + " Age: " + Age.ToString();
}
}
//②複数人の集団を管理するPeopleクラス
class People
{
ArrayList PersonList = new ArrayList();
public void AddPerson(Person oPeople)
{
PersonList.Add(oPeople);
}
}
class Program
{
static void Main(string[] args)
{
//Peopleクラス(複数人の集団)のインスタンス作成
People plist = new People();
//Personクラス(個人)のインスタンス作成
Person p1 = new Person("Suzuki", "Hanako", 29);
Person p2 = new Person("Yamada", "Taro", 19);
//People(集団)にPerson(個人)を追加
plist.AddPerson(p1);
plist.AddPerson(p2);
Console.WriteLine("### foreachを用いてPersonsを数え上げ開始 ###");
foreach (Person person in plist)
{
Console.WriteLine(person);
}
}
}
}
エラー CS1579 foreach ステートメントは、'People' が 'GetEnumerator' のパブリック インスタンス定義を含んでいないため、型 'People' の変数に対して使用できません
(図131)エラー

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IEnumeratorTest2
{
//①個人を管理するPersonクラス
class Person
{
private string FirstName;
private string LastName;
private int Age;
public Person(string firstName, string lastName, int age)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
}
public override string ToString()
{
return "Name:" + FirstName + " " + LastName + " Age: " + Age.ToString();
}
}
//②複数人の集団を管理するPeopleクラス
class People : IEnumerable, IEnumerator
{
ArrayList PersonList = new ArrayList();
public void AddPerson(Person oPeople)
{
PersonList.Add(oPeople);
}
// (1) IEnumerableの実装(★追記)
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
// (2) IEnumeratorの実装(★追記)
// 現在位置(カレントポジション)の変数定義
private int CurrPosition = -1;
// (2-1) void Reset()メソッド(★追記)
public bool MoveNext()
{
if (CurrPosition < PersonList.Count - 1)
{
++CurrPosition;
return true;
}
return false;
}
// (2-2) bool MoveNext()メソッドの実装(★追記)
public void Reset()
{
CurrPosition = -1;
}
// (2-3) object Current()メソッドの実装(★追記)
public object Current
{
get
{
return PersonList[CurrPosition];
}
}
}
class Program
{
static void Main(string[] args)
{
//Peopleクラス(複数人の集団)のインスタンス作成
People plist = new People();
//Personクラス(個人)のインスタンス作成
Person p1 = new Person("Suzuki", "Hanako", 29);
Person p2 = new Person("Yamada", "Taro", 19);
//People(集団)にPerson(個人)を追加
plist.AddPerson(p1);
plist.AddPerson(p2);
Console.WriteLine("### foreachを用いてPersonsを数え上げ開始 ###");
foreach (Person person in plist)
{
Console.WriteLine(person);
}
}
}
}
(図132)
