foreach ステートメントで Visual C# クラスを使用できるようにします

この記事では、 インターフェイスと インターフェイスを使用 IEnumerable して、 IEnumerator ステートメントで使用できるクラスを作成する方法について foreach 説明します。

元の製品バージョン: Visual Studio
元の KB 番号: 322022

IEnumerator インターフェイス

IEnumerableIEnumerator は一緒に頻繁に使用されます。 これらのインターフェイスは似ていますが (名前も似ていますが)、目的は異なります。

インターフェイスは IEnumerator 、クラスの内部にあるコレクションに対して反復機能を提供します。 IEnumerator では、次の 3 つのメソッドを実装する必要があります。

  • MoveNextコレクションインデックスを 1 ずつインクリメントし、コレクションの末尾に達したかどうかを示すブール値を返す メソッド。

  • Resetコレクション インデックスを初期値の -1 にリセットする メソッド。 これにより、列挙子が無効になります。

  • 現在の Current オブジェクトを 返す メソッド 。position

    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 許可します。 ただし、 GetEnumerator インターフェイスの メソッドは IEnumerable インターフェイスを IEnumerator 返します。 そのため、 を実装 IEnumerableするには、 も実装 IEnumeratorする必要があります。 を実装IEnumeratorしない場合は、 メソッドIEnumerableから インターフェイスに戻り値をGetEnumeratorIEnumeratorキャストすることはできません。

要約すると、 を IEnumerable 使用するには、 クラスが を実装 IEnumeratorする必要があります。 のサポートを提供する場合は、両方のインターフェイスを foreach実装します。

ステップ バイ ステップの例

次の例では、これらのインターフェイスを使用する方法を示します。 この例では、 IEnumerator インターフェイスと IEnumerable インターフェイスを という名前 carsのクラスで使用します。 クラスには cars 、オブジェクトの car 内部配列があります。 クライアント アプリケーションは、これら 2 つのインターフェイスの実装のために、 コンストラクトを foreach 使用して、この内部配列を列挙できます。

  1. Visual C# で新しいコンソール アプリケーション プロジェクトを作成するには、次の手順に従います。

    1. Microsoft Visual Studio .NET または Visual Studio を起動します。
    2. [ ファイル] メニューの [ 新規] をポイントし、[ プロジェクト] をクリックします。
    3. [プロジェクトの種類] で [Visual C# プロジェクト] をクリックし、[テンプレート] で [コンソール アプリケーション] をクリックします。
    4. [ 名前 ] ボックスに「 ConsoleEnum」と入力します。
  2. 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();
           }
       }
    }
    
  3. [プロジェクト] メニューの [クラスの追加] をクリックし、[名前] ボックスに「car」と入力します。

  4. 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
    
  5. [プロジェクト] メニューの [クラスの追加] をクリックして別のクラスをプロジェクトに追加し、[名前] ボックスに「cars」と入力します。

  6. 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];}
           }
        }
      }
    
  7. プロジェクトを実行します。

コンソール ウィンドウに次の出力が表示されます。

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