誰かがIEnumerableとIEnumeratorを私に説明できますか?[閉まっている]


272

誰かがIEnumerableとIEnumeratorを私に説明できますか?

たとえば、foreachでいつ使用するのですか?IEnumerableとIEnumeratorの違いは何ですか?なぜそれを使用する必要があるのですか?


55
これは、JavaとJavaScript以来の最悪のネーミングミックスアップです
Matthew Lock

@MatthewLockはあなたが何を意味するのか説明できますか?
David Klempfner、

回答:


275

たとえば、foreachでいつ使用するのですか?

IEnumerable"over" は使用しませんforeach。実装IEnumerableすることでforeach 可能になります。

次のようなコードを書く場合:

foreach (Foo bar in baz)
{
   ...
}

機能的には次のように記述します。

IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
   bar = (Foo)bat.Current
   ...
}

「機能的に同等」とは、コンパイラが実際にコードを変換することです。を実装しない限り、この例ではforeachon bazを使用できません。 bazIEnumerable

IEnumerablebazメソッドを実装することを意味します

IEnumerator GetEnumerator()

IEnumeratorこのメソッドが返すメソッドを実装しなければならないことをオブジェクト

bool MoveNext()

そして

Object Current()

最初のメソッドIEnumerableは、列挙子を作成したオブジェクトの次のオブジェクトに進み、false完了した場合は戻り、2番目のメソッドは現在のオブジェクトを返します。

実装で反復できる.NetのすべてのものIEnumerable。独自のクラスを構築していて、それがを実装するクラスからまだ継承していないIEnumerable場合はforeach、実装してIEnumerable(および新しいGetEnumeratorメソッドが返す列挙子クラスを作成することにより)クラスをステートメントで使用できるようにすることができます。


15
元の投稿者が「over foreach」と言ったとき、彼は「foreachループを使用するのではなく、明示的にGetEnumerator()/ MoveNext()をいつ呼び出す必要があるか」を意味していたと思います。それが価値があるもののために。
mqp 2009

6
ああ、そうだと思います。ええ、私の投稿では答えは暗黙的です。それはコンパイラーがとにかく行うことなので、それは問題ではありません。つまり、最も簡単な方法、つまりforeachを使用してください。
ロバートロスニー、2009

12
この答えはすべての話を語っていません。EnumerableオブジェクトはIEnumerableを実装する必要はありません。必要なのは、任意の型のbool MoveNext()メソッドとCurrentプロパティを持つ型のインスタンスを返すGetEnumeratorメソッドだけです。この「ダックタイピング」アプローチは、値型コレクションを列挙するときにボックス化を回避する方法としてC#1.0で実装されました。
phoog 2012年

3
上からの説明とWorkthrough:Implementing IEnumerable of(T)の作業により、優れたソースが手に入ります。
ruedi 2013年

4
これはC ++のようなものiteratorですか?
Matt G

161

IEnumerableおよびIEnumeratorインターフェイス

既存の.NETインターフェイスを実装するプロセスの調査を開始するために、まずIEnumerableとIEnumeratorの役割を見てみましょう。C#がforeachという名前のキーワードをサポートしていることを思い出してください。これにより、任意の配列型のコンテンツを反復処理できます。

// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
   Console.WriteLine(i);
}

配列型だけがこの構造を利用できるように見えるかもしれませんが、問題の真実は、GetEnumerator()という名前のメソッドをサポートするすべての型がforeach構造によって評価できることです。説明のために、私に従ってください!

Garageクラスがあるとします。

// Garage contains a set of Car objects.
public class Garage
{
   private Car[] carArray = new Car[4];
   // Fill with some Car objects upon startup.
   public Garage()
   {
      carArray[0] = new Car("Rusty", 30);
      carArray[1] = new Car("Clunker", 55);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
}

理想的には、データ値の配列のように、foreach構文を使用してGarageオブジェクトのサブアイテムを反復処理すると便利です。

// This seems reasonable ...
public class Program
{
   static void Main(string[] args)
   {
      Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
      Garage carLot = new Garage();
      // Hand over each car in the collection?
      foreach (Car c in carLot)
      {
         Console.WriteLine("{0} is going {1} MPH",
         c.PetName, c.CurrentSpeed);
      }
      Console.ReadLine();
   }
}

悲しいことに、コンパイラは、GarageクラスがGetEnumerator()という名前のメソッドを実装していないことを通知します。このメソッドは、System.Collections名前空間内に潜むIEnumerableインターフェイスによって形式化されます。この動作をサポートするクラスまたは構造は、含まれているサブアイテムを呼び出し元に公開できることをアドバタイズします(この例では、foreachキーワード自体)。この標準.NETインターフェースの定義は次のとおりです。

// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
   IEnumerator GetEnumerator();
}

ご覧のとおり、GetEnumerator()メソッドは、System.Collections.IEnumeratorという名前のさらに別のインターフェイスへの参照を返します。このインターフェイスは、呼び出し元がIEnumerable互換コンテナーに含まれる内部オブジェクトをトラバースできるようにするインフラストラクチャを提供します。

// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
   bool MoveNext (); // Advance the internal position of the cursor.
   object Current { get;} // Get the current item (read-only property).
   void Reset (); // Reset the cursor before the first member.
}

これらのインターフェースをサポートするようにガレージタイプを更新する場合は、長い道のりを取り、各メソッドを手動で実装できます。GetEnumerator()、MoveNext()、Current、Reset()のカスタマイズバージョンを自由に提供できますが、もっと簡単な方法があります。System.Array型(および他の多くのコレクションクラス)は既にIEnumerableとIEnumeratorを実装しているため、次のように単純に要求をSystem.Arrayに委任できます。

using System.Collections;
...
public class Garage : IEnumerable
{
   // System.Array already implements IEnumerator!
   private Car[] carArray = new Car[4];
   public Garage()
   {
      carArray[0] = new Car("FeeFee", 200);
      carArray[1] = new Car("Clunker", 90);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
   public IEnumerator GetEnumerator()
   {
      // Return the array object's IEnumerator.
      return carArray.GetEnumerator();
   }
}

Garageタイプを更新したら、C#のforeachコンストラクト内でタイプを安全に使用できます。さらに、GetEnumerator()メソッドがパブリックに定義されている場合、オブジェクトユーザーはIEnumeratorタイプと対話することもできます。

// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);

ただし、IEnumerableの機能をオブジェクトレベルから非表示にしたい場合は、明示的なインターフェイス実装を利用するだけです。

IEnumerator IEnumerable.GetEnumerator()
{
  // Return the array object's IEnumerator.
  return carArray.GetEnumerator();
}

そうすることで、カジュアルオブジェクトのユーザーはGarageのGetEnumerator()メソッドを見つけることができなくなり、必要に応じてforeachコンストラクトがバックグラウンドでインターフェースを取得します。

Pro C#5.0および.NET 4.5 Frameworkから適応


1
素晴らしい答え、ありがとう!質問が1つあります。最初の例では、foreachを使用して配列をループしますが、2番目の例ではループを実行できません。配列がクラス内にあるためか、オブジェクトが含まれているためですか?
Caleb Palmquist 2017年

素晴らしい説明ありがとうございます。私の唯一の質問は、なぜ単にメソッドGarageを取得しcarArrayないのかということです。そうすればGetEnumeratorArrayすでに実装しているので、自分で実装する必要はありません。例foreach(Car c in carLot.getCars()) { ... }
Nick Rolando

63

IEnumerableを実装するということは、クラスがIEnumeratorオブジェクトを返すことを意味します。

public class People : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        // return a PeopleEnumerator
    }
}

IEnumeratorを実装するということは、クラスが反復のためのメソッドとプロパティを返すことを意味します。

public class PeopleEnumerator : IEnumerator
{
    public void Reset()...

    public bool MoveNext()...

    public object Current...
}

それがとにかく違いです。


1
これは、他の投稿とともに、クラスを「foreach」を使用してその内容を反復できるクラスに変換する方法を説明しています。
Contango、2010年

54

類推による説明+コードのウォークスルー

最初にコードなしの説明、次に後で追加します。

あなたが航空会社を経営しているとしましょう。そして、各飛行機であなたは飛行機を飛んでいる乗客についての情報を知りたいです。基本的に、飛行機を「横切る」ことができるようにしたいです。つまり、前部座席から出発して、飛行機の後方に向かって作業し、乗客に情報を尋ねます。たとえば、誰であるか、どこから来たのかなどです。飛行機はこれしかできません、 もしそれが:

  1. 可算
  2. カウンターがある場合。

なぜこれらの要件なのか?それがインターフェースに必要なものだからです。

これが情報の過多である場合、知っておく必要があるのは、飛行機の各乗客に最初から最後までいくつか質問できることです。

カウント可能とはどういう意味ですか?

航空会社が「カウント可能」である場合、これは飛行機に客室乗務員が存在しなければならず、その唯一の仕事はカウントすることであり、この客室乗務員は非常に具体的な方法でカウントする必要があることを意味します。

  1. カウンター/フライトアテンダントは、最初の乗客の前に開始する必要があります(安全をデモするすべての人の前で、ライフジャケットの着用方法など)。
  2. 彼/彼女(すなわち客室乗務員)は通路を最初の席に「移動」しなければなりません。
  3. 彼/彼女はそれから記録することになっています:(i)人が座席にいる、そして(ii)通路の彼らの現在の位置。

カウント手順

航空会社の船長は、すべての乗客について、調査またはカウントされた時点でのレポートを求めています。したがって、最初の席の人に話しかけた後、客室乗務員/カウンターは機長に報告し、報告が与えられると、カウンターは通路内の正確な位置を記憶し、彼/彼女が去った場所で右カウントを続けますオフ。

このようにして、船長は常に調査中の現在の人物に関する情報を持つことができます。そうすれば、この個人がマンチェスターシティが好きだとわかった場合、その乗客に優遇措置を与えることができます。

  • カウンターは飛行機の端に到達するまで続きます。

これをIEnumerablesと関連付けましょう

  • 列挙可能とは、飛行機の乗客の集まりです。民間航空法-これらは基本的にすべてのIEnumerableが従わなければならない規則です。航空会社のアテンダントが乗客情報を携えて船長に行くたびに、私たちは基本的に乗客を船長に「譲ります」。機長は基本的に、飛行機で乗客を並べ替えることを除いて、彼が乗客とやりたいことは何でもできる。この場合、マンチェスターシティをフォローすると、優遇措置が与えられます(ハァッ!)

    foreach (Passenger passenger in Plane)
    // the airline hostess is now at the front of the plane
    // and slowly making her way towards the back
    // when she get to a particular passenger she gets some information
    // about the passenger and then immediately heads to the cabin
    // to let the captain decide what to do with it
    { // <---------- Note the curly bracket that is here.
        // we are now cockpit of the plane with the captain.
        // the captain wants to give the passenger free 
        // champaign if they support manchester city
        if (passenger.supports_mancestercity())
        {
            passenger.getFreeChampaign();
        } else
        {
            // you get nothing! GOOD DAY SIR!
        }
    } //  <---- Note the curly bracket that is here!
          the hostess has delivered the information 
          to the captain and goes to the next person
          on the plane (if she has not reached the 
          end of the plane)
    

概要

つまり、カウンターがあればカウント可能です。そしてカウンターは(基本的に):(i)その場所(状態)を覚えている、(ii)次に移動できる、(iii)彼が扱っている現在の人について知っている。

Enumerableは、「カウント可能」の単なる空想的な言葉です。言い換えると、列挙型を使用すると、「列挙」(つまり、カウント)できます。


23

IEnumerableはGetEnumeratorを実装します。呼び出されると、そのメソッドはMoveNext、Reset、およびCurrentを実装するIEnumeratorを返します。

したがって、クラスがIEnumerableを実装する場合、メソッド(GetEnumerator)を呼び出して、foreachなどのループで使用できる新しいオブジェクト(IEnumerator)を返すことができるということです。


18

IEnumerableを実装すると、リストのIEnumeratorを取得できます。

IEnumeratorは、yieldキーワードを使用して、リスト内の項目にforeachスタイルの順次アクセスを許可します。

foreach実装(Java 1.4など)の前に、リストを反復する方法は、リストから列挙子を取得し、次の値が返される限り、リストの「次の」項目を要求することでした。アイテムはnullではありません。Foreachは、lock()が舞台裏でMonitorクラスを実装するのと同じ方法で、それを暗黙的に言語機能として実行します。

IEnumerableを実装しているため、リストでforeachが機能することを期待しています。


リストの場合、なぜforeachを使用できないのですか?
prodev42 2009

.Net duckはforeachステートメントを入力しますが、IEnumerable / IEnumerable <T>は、クラスを列挙できると言える適切な方法です。
user7116 2009

15
  • IEnumerableを実装するオブジェクトを使用すると、他のユーザーが(列挙子によって)そのアイテムのそれぞれにアクセスできます。
  • IEnumeratorを実装するオブジェクトは、反復処理を実行します。列挙可能なオブジェクトをループしています。

リスト、スタック、ツリーのような列挙可能なオブジェクトについて考えてください。


12

IEnumerableとIEnumerator(およびそれらに対応する一般的なIEnumerable <T>とIEnumerator <T>)は、.Net Framework Class Librayコレクションの反復子実装の基本インターフェイスです。

IEnumerableは、世の中にあるコードの大部分で見られる最も一般的なインターフェースです。これは、foreachループ、ジェネレーター(yieldと考えます)を有効にし、その小さなインターフェースのために、厳密な抽象化を作成するために使用されます。IEnumerableはIEnumeratorに依存します。

一方、IEnumeratorは、わずかに低いレベルの反復インターフェースを提供します。これは明示的なイテレータと呼ばれ、反復サイクルをプログラマがより細かく制御できるようにします。

IEnumerable

IEnumerableは、それをサポートするコレクションの反復を可能にする標準インターフェイスです(実際、今日考えることができるすべてのコレクション型は、IEnumerableを実装しています)。コンパイラのサポートにより、などの言語機能が可能になりますforeach。一般的には、この暗黙の反復子の実装が可能になります

foreachループ

foreach (var value in list)
  Console.WriteLine(value);

foreachループはIEnumerableインターフェイスを使用する主な理由の1つだと思います。さまざまな変数をチェックして何をしているのかを確認する必要があるforeach従来のCスタイルのループと比較して、構文は非常に簡潔で非常に理解しやすいです。

キーワード

おそらくあまり知られていない機能は、IEnumerableがand ステートメントを使用してC#のジェネレーターも有効にすることです。yield returnyield break

IEnumerable<Thing> GetThings() {
   if (isNotReady) yield break;
   while (thereIsMore)
     yield return GetOneMoreThing();
}

抽象化

実際のもう1つの一般的なシナリオは、IEnumerableを使用して最小限の抽象化を提供することです。これは非常に小さく読み取り専用のインターフェイスであるため、コレクションをIEnumerableとして公開することをお勧めします(たとえば、リストではありません)。そうすれば、クライアントのコードを壊すことなく、実装を自由に変更できます(たとえば、リストをLinkedListに変更します)。

ゴッチャ

注意すべき動作の1つは、ストリーミングの実装(たとえば、最初にすべての結果をメモリにロードするのではなく、データベースから行ごとにデータを取得する)では、コレクションを2回以上繰り返すことができないことです。これは、問題なく複数回反復できるListなどのメモリ内コレクションとは対照的です。たとえば、ReSharperにはIEnumerableの可能な複数の列挙のコードインスペクションがあります

IEnumerator

一方、IEnumeratorは、IEnumerble-foreach-magicを機能させる舞台裏のインターフェースです。厳密に言えば、明示的なイテレータを使用できます。

var iter = list.GetEnumerator();
while (iter.MoveNext())
    Console.WriteLine(iter.Current);

私の経験では、IEnumeratorはより冗長な構文とわずかに混乱するセマンティクスのため、一般的なシナリオではめったに使用されません(少なくとも私にとっては、たとえばMoveNext()も値を返しますが、名前はまったく示唆していません)。

IEnumeratorの使用例

私は使用のIEnumeratorを私が提供された特定の(わずかに低いレベル)のライブラリーとフレームワーク内のIEnumerableインターフェイスを。一例は、データストリーム処理ライブラリで、foreachさまざまなファイルストリームとシリアル化を使用してデータが収集されたにもかかわらず、ループ内で一連のオブジェクトを提供していました。

クライアントコード

foreach(var item in feed.GetItems())
    Console.WriteLine(item);

図書館

IEnumerable GetItems() {
    return new FeedIterator(_fileNames)
}

class FeedIterator: IEnumerable {
    IEnumerator GetEnumerator() {
        return new FeedExplicitIterator(_stream);
    }
}

class FeedExplicitIterator: IEnumerator {
    DataItem _current;

    bool MoveNext() {
        _current = ReadMoreFromStream();
        return _current != null;           
    }

    DataItem Current() {
        return _current;   
    }
}

9

実装IEnumerableとは、本質的にオブジェクトを繰り返し処理できることを意味します。インデックスを作成できない特定のリストがありますが、それらを列挙することができるため、これは必ずしも配列であることを意味しません。

IEnumerator反復の実行に使用される実際のオブジェクトです。リスト内のあるオブジェクトから次のオブジェクトへの移動を制御します。

ほとんどの場合、IEnumerableIEnumeratorforeachループの一部として透過的に使用されます。


6

IEnumerableとIEnumeratorの違い:

  • IEnumerableはIEnumeratorを内部的に使用します。
  • IEnumerableは、実行中のアイテム/オブジェクトを認識していません。
  • IEnumeratorを別の関数に渡すと、アイテム/オブジェクトの現在の位置がわかります。
  • IEnumerableコレクションを別の関数に渡すと、アイテム/オブジェクトの現在の位置がわかりません(実行中のアイテムがわかりません)。

    IEnumerableにはGetEnumerator()メソッドが1つあります

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

IEnumeratorには、Currentと呼ばれる1つのプロパティと、Reset()とMoveNext()という2つのメソッドがあります(リスト内のアイテムの現在の位置を知るのに役立ちます)。

public interface IEnumerator
{
     object Current { get; }
     bool MoveNext();
     void Reset();
}

5

IEnumerableは、Ienumeratorを含むボックスです。IEnumerableは、すべてのコレクションの基本インターフェイスです。コレクションがIEnumerableを実装している場合、foreachループは機能します。以下のコードでは、独自の列挙子を持つステップを説明しています。まず、コレクションを作成するクラスを定義しましょう。

public class Customer
{
    public String Name { get; set; }
    public String City { get; set; }
    public long Mobile { get; set; }
    public double Amount { get; set; }
}

次に、Customerクラスのコレクションとして機能するClassを定義します。IEnumerableインターフェースを実装していることに注意してください。したがって、メソッドGetEnumeratorを実装する必要があります。これにより、カスタムの列挙子が返されます。

public class CustomerList : IEnumerable
{
    Customer[] customers = new Customer[4];
    public CustomerList()
    {
        customers[0] = new Customer { Name = "Bijay Thapa", City = "LA", Mobile = 9841639665, Amount = 89.45 };
        customers[1] = new Customer { Name = "Jack", City = "NYC", Mobile = 9175869002, Amount = 426.00 };
        customers[2] = new Customer { Name = "Anil min", City = "Kathmandu", Mobile = 9173694005, Amount = 5896.20 };
        customers[3] = new Customer { Name = "Jim sin", City = "Delhi", Mobile = 64214556002, Amount = 596.20 };
    }

    public int Count()
    {
        return customers.Count();
    }
    public Customer this[int index]
    {
        get
        {
            return customers[index];
        }
    }
    public IEnumerator GetEnumerator()
    {
        return customers.GetEnumerator(); // we can do this but we are going to make our own Enumerator
        return new CustomerEnumerator(this);
    }
}

次のように、独自のカスタム列挙子を作成します。したがって、MoveNextメソッドを実装する必要があります。

 public class CustomerEnumerator : IEnumerator
    {
        CustomerList coll;
        Customer CurrentCustomer;
        int currentIndex;
        public CustomerEnumerator(CustomerList customerList)
        {
            coll = customerList;
            currentIndex = -1;
        }

        public object Current => CurrentCustomer;

        public bool MoveNext()
        {
            if ((currentIndex++) >= coll.Count() - 1)
                return false;
            else
                CurrentCustomer = coll[currentIndex];
            return true;
        }

        public void Reset()
        {
            // we dont have to implement this method.
        }
    }

これで、以下のようにコレクションに対してforeachループを使用できます。

    class EnumeratorExample
    {
        static void Main(String[] args)
        {

            CustomerList custList = new CustomerList();
            foreach (Customer cust in custList)
            {
                Console.WriteLine("Customer Name:"+cust.Name + " City Name:" + cust.City + " Mobile Number:" + cust.Amount);
            }
            Console.Read();

        }
    }

4

イテレーターパターンを理解しておくと役に立ちます。同じものを読むことをお勧めします。

イテレーターパターン

高レベルでは、反復子パターンを使用して、任意のタイプのコレクションを反復する標準的な方法を提供できます。イテレーターパターンには、実際のコレクション(クライアント)、アグリゲーター、イテレーターの3人の参加者がいます。集約は、イテレータを返すメソッドを持つインターフェース/抽象クラスです。イテレーターは、コレクションを反復処理できるメソッドを持つインターフェース/抽象クラスです。

パターンを実装するには、まず、関係するコレクション(クライアント)を反復処理できる具象を生成するイテレーターを実装する必要があります。次に、コレクション(クライアント)がアグリゲーターを実装して、上記のイテレーターのインスタンスを返します。

これがUMLダイアグラムです イテレーターパターン

したがって、基本的にc#では、IEnumerableは抽象集計であり、IEnumeratorは抽象Iteratorです。IEnumerableには、目的のタイプのIEnumeratorのインスタンスを作成する単一のメソッドGetEnumeratorがあります。リストのようなコレクションはIEnumerableを実装します。

例。我々は方法があるとしますgetPermutations(inputString)文字列のリターンすべての順列ことやメソッドがのインスタンスを返すことIEnumerable<string>

順列の数を数えるために、以下のようなことができます。

 int count = 0;
        var permutations = perm.getPermutations(inputString);
        foreach (string permutation in permutations)
        {
            count++;
        }

c#コンパイラは、多かれ少なかれ、上記を

using (var permutationIterator = perm.getPermutations(input).GetEnumerator())
        {
            while (permutationIterator.MoveNext())
            {
                count++;
            }
        }

ご不明な点がございましたら、お気軽にお問い合わせください。


2

マイナーな貢献。

彼らの多くが「いつ使うか」と「foreachで使う」について説明しているように。IEnumerableとIEnumeratorの違いについて質問されたとおり、ここにAnother States Differenceを追加することを考えました。

以下のディスカッションスレッドに基づいて、以下のコードサンプルを作成しました。

IEnumerable、IEnumeratorとforeach、 IEnumeratorとIEnumerableの違いはですか?

Enumeratorは関数呼び出し間の状態(反復位置)を保持しますが、Enumerableは反復を保持しません。

これは、理解すべきコメント付きのテスト済みの例です。

専門家が私を追加/修正してください。

static void EnumerableVsEnumeratorStateTest()
{
    IList<int> numList = new List<int>();

    numList.Add(1);
    numList.Add(2);
    numList.Add(3);
    numList.Add(4);
    numList.Add(5);
    numList.Add(6);

    Console.WriteLine("Using Enumerator - Remembers the state");
    IterateFrom1to3(numList.GetEnumerator());

    Console.WriteLine("Using Enumerable - Does not Remembers the state");
    IterateFrom1to3Eb(numList);

    Console.WriteLine("Using Enumerable - 2nd functions start from the item 1 in the collection");
}

static void IterateFrom1to3(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());

        if (numColl.Current > 3)
        {
            // This method called 3 times for 3 items (4,5,6) in the collection. 
            // It remembers the state and displays the continued values.
            IterateFrom3to6(numColl);
        }
    }
}

static void IterateFrom3to6(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());
    }
}

static void IterateFrom1to3Eb(IEnumerable<int> numColl)
{
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());

        if (num>= 5)
        {
            // The below method invokes for the last 2 items.
            //Since it doesnot persists the state it will displays entire collection 2 times.
            IterateFrom3to6Eb(numColl);
        }
    }
}

static void IterateFrom3to6Eb(IEnumerable<int> numColl)
{
    Console.WriteLine();
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());
    }
}

2

私はこれらの違いに気づきました:

A.別の方法でリストを反復処理します。foreachはIEnumerableに使用でき、whileループはIEnumeratorに使用できます。

B. IEnumeratorは、あるメソッドから別のメソッドに渡したときに現在のインデックスを記憶できます(現在のインデックスで作業を開始します)が、IEnumerableはインデックスを記憶できず、インデックスを最初にリセットします。このビデオの詳細https://www.youtube.com/watch?v=jd3yUjGc9M0


1

IEnumerableそして、IEnumeratorの両方がC#のインターフェイスです。

IEnumerableインターフェースGetEnumerator()を返す単一のメソッドを定義するIEnumeratorインターフェースです。

これIEnumerableは、foreachステートメントで使用できるを実装するコレクションへの読み取り専用アクセスで機能します。

IEnumeratorには2つのメソッドがMoveNextありResetます。また、というプロパティもありますCurrent

以下は、IEnumerableとIEnumeratorの実装を示しています。


0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Enudemo
{

    class Person
    {
        string name = "";
        int roll;

        public Person(string name, int roll)
        {
            this.name = name;
            this.roll = roll;
        }

        public override string ToString()
        {
            return string.Format("Name : " + name + "\t Roll : " + roll);
        }

    }


    class Demo : IEnumerable
    {
        ArrayList list1 = new ArrayList();

        public Demo()
        {
            list1.Add(new Person("Shahriar", 332));
            list1.Add(new Person("Sujon", 333));
            list1.Add(new Person("Sumona", 334));
            list1.Add(new Person("Shakil", 335));
            list1.Add(new Person("Shruti", 336));
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
           return list1.GetEnumerator();
        }
    }



    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();  // Notice here. it is simple object but for 
                                //IEnumerator you can get the collection data

            foreach (Person X in d)
            {
                Console.WriteLine(X);
            }

            Console.ReadKey();
        }
    }
}
/*
Output : 

Name : Shahriar  Roll : 332
Name : Sujon     Roll : 333
Name : Sumona    Roll : 334
Name : Shakil    Roll : 335
Name : Shruti    Roll : 336
  */
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.