この記事では、 IEnumerable
インターフェイスと IEnumerator
インターフェイスを使用して、 foreach
ステートメントで使用できるクラスを作成する方法について説明します。
元の製品バージョン: Visual Studio
元の KB 番号: 322022
IEnumerator インターフェイス
IEnumerable
と IEnumerator
は頻繁に一緒に使用されます。 これらのインターフェイスは似ていますが (名前も似ていますが)、目的は異なります。
IEnumerator
インターフェイスは、クラスの内部にあるコレクションに対して反復的な機能を提供します。 IEnumerator
では、次の 3 つのメソッドを実装する必要があります。
MoveNext
メソッド。コレクション インデックスを 1 ずつインクリメントし、コレクションの末尾に達したかどうかを示すブール値を返します。Reset
メソッド。コレクション インデックスを初期値 -1 にリセットします。 これにより、列挙子が無効になります。position
の現在のオブジェクトを返すCurrent
メソッド。public bool MoveNext() { position++; return (position < carlist.Length); } public void Reset() { position = -1; } public object Current { get { return carlist[position];} }
IEnumerable インターフェイス
IEnumerable
インターフェイスは、foreach
イテレーションのサポートを提供します。 IEnumerable
では、 GetEnumerator
メソッドを実装する必要があります。
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
どのインターフェイスを使用するか
最初は、これらのインターフェイスを使用するとわかりにくい場合があります。 IEnumerator
インターフェイスは、クラス内のコレクション型オブジェクトに対する反復処理を提供します。 IEnumerable
インターフェイスは、foreach
ループを使用して列挙を許可します。 ただし、IEnumerable
インターフェイスの GetEnumerator
メソッドは、IEnumerator
インターフェイスを返します。 そのため、 IEnumerable
を実装するには、 IEnumerator
も実装する必要があります。 IEnumerator
を実装しない場合は、IEnumerable
のGetEnumerator
メソッドからIEnumerator
インターフェイスに戻り値をキャストすることはできません。
要約すると、 IEnumerable
を使用するには、クラスが IEnumerator
を実装する必要があります。 foreach
のサポートを提供する場合は、両方のインターフェイスを実装します。
手順の例
次の例では、これらのインターフェイスを使用する方法を示します。 この例では、 IEnumerator
インターフェイスと IEnumerable
インターフェイスが cars
という名前のクラスで使用されます。 cars
クラスには、car
オブジェクトの内部配列があります。 クライアント アプリケーションでは、これら 2 つのインターフェイスの実装により、 foreach
コンストラクトを使用して、この内部配列を列挙できます。
Visual C# で新しいコンソール アプリケーション プロジェクトを作成するには、次の手順に従います。
- Microsoft Visual Studio .NET または Visual Studio を起動します。
- [ファイル] メニューの [新規作成] をポイントし、 [プロジェクト] をクリックします。
- プロジェクトの種類の下の Visual C# プロジェクトをクリックし、Templates の下にある Console Application をクリックします。
- [ 名 ボックスに「 ConsoleEnum」と入力します。
Class1.csの名前を host.cs に変更し、host.csのコードを次のコードに置き換えます。
using System; namespace ConsoleEnum { class host { [STAThread] static void Main(string[] args) { cars C = new cars(); Console.WriteLine("\nInternal Collection (Unsorted - IEnumerable,Enumerator)\n"); foreach(car c in C) Console.WriteLine(c.Make + "\t\t" + c.Year); Console.ReadLine(); } } }
[Project メニューの クラスの追加] をクリックし、[Name ボックスに「car」と入力します。
car.csのコードを次のコードに置き換えます。
using System; using System.Collections; namespace ConsoleEnum { public class car { private int year; private string make; public car(string Make,int Year) { make=Make; year=Year; } public int Year { get {return year;} set {year=value;} } public string Make { get {return make;} set {make=value;} } }//end class }//end namespace
[Project メニューの クラスの追加 をクリックしてプロジェクトに別のクラスを追加し、Name ボックスに「cars」と入力します。
cars.csのコードを次のコードに置き換えます。
using System; using System.Collections; namespace ConsoleEnum { public class cars : IEnumerator,IEnumerable { private car[] carlist; int position = -1; //Create internal array in constructor. public cars() { carlist= new car[6] { new car("Ford",1992), new car("Fiat",1988), new car("Buick",1932), new car("Ford",1932), new car("Dodge",1999), new car("Honda",1977) }; } //IEnumerator and IEnumerable require these methods. public IEnumerator GetEnumerator() { return (IEnumerator)this; } //IEnumerator public bool MoveNext() { position++; return (position < carlist.Length); } //IEnumerable public void Reset() { position = -1; } //IEnumerable public object Current { get { return carlist[position];} } } }
プロジェクトを実行します。
Console ウィンドウに次の出力が表示されます。
Ford 1992
Fiat 1988
Buick 1932
Ford 1932
Dodge 1999
Honda 1977
ベスト プラクティス
この記事の例は、これらのインターフェイスの使用方法をよりよく説明するために、できるだけシンプルに保たれています。 コードの堅牢性を高め、コードで現在のベスト プラクティス ガイドラインが使用されるようにするには、次のようにコードを変更します。
- 複数の列挙子を作成できるように、入れ子になったクラスに
IEnumerator
を実装します。 IEnumerator
のCurrent
メソッドの例外処理を指定します。 コレクションの内容が変更されると、reset
メソッドが呼び出されます。 その結果、現在の列挙子が無効になり、IndexOutOfRangeException
例外が発生します。 その他の状況でも、この例外が発生する可能性があります。 そのため、Try...Catch
ブロックを実装して、この例外をキャッチし、InvalidOperationException
例外を発生させます。
using System;
using System.Collections;
namespace ConsoleEnum
{
public class cars : IEnumerable
{
private car[] carlist;
//Create internal array in constructor.
public cars()
{
carlist= new car[6]
{
new car("Ford",1992),
new car("Fiat",1988),
new car("Buick",1932),
new car("Ford",1932),
new car("Dodge",1999),
new car("Honda",1977)
};
}
//private enumerator class
private class MyEnumerator:IEnumerator
{
public car[] carlist;
int position = -1;
//constructor
public MyEnumerator(car[] list)
{
carlist=list;
}
private IEnumerator getEnumerator()
{
return (IEnumerator)this;
}
//IEnumerator
public bool MoveNext()
{
position++;
return (position < carlist.Length);
}
//IEnumerator
public void Reset()
{
position = -1;
}
//IEnumerator
public object Current
{
get
{
try
{
return carlist[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
} //end nested class
public IEnumerator GetEnumerator()
{
return new MyEnumerator(carlist);
}
}
}