この記事では、 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);
}
}
}