Adakah yang bisa menjelaskan IEnumerable dan IEnumerator kepada saya? [Tutup]


272

Adakah yang bisa menjelaskan IEnumerable dan IEnumerator kepada saya?

misalnya, kapan menggunakannya lebih dulu? apa perbedaan antara IEnumerable dan IEnumerator? Mengapa kita perlu menggunakannya?


55
Ini adalah mixup penamaan terburuk sejak Java dan JavaScript
Matthew Lock

@ MatthewLock dapatkah Anda menjelaskan maksud Anda?
David Klempfner

Jawaban:


275

misalnya, kapan menggunakannya lebih dulu?

Anda tidak menggunakan IEnumerable"lebih" foreach. Pelaksana IEnumerablemembuat menggunakan foreach mungkin .

Ketika Anda menulis kode seperti:

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

itu secara fungsional setara dengan menulis:

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

Dengan "setara secara fungsional," Maksud saya sebenarnya kompiler mengubah kode menjadi. Anda tidak dapat menggunakan foreachpada bazdalam contoh ini kecuali baz alat IEnumerable.

IEnumerableberarti bazmengimplementasikan metode

IEnumerator GetEnumerator()

The IEnumeratorobjek yang metode ini kembali harus menerapkan metode

bool MoveNext()

dan

Object Current()

Metode pertama maju ke objek berikutnya di IEnumerableobjek yang membuat enumerator, kembali falsejika sudah selesai, dan yang kedua mengembalikan objek saat ini.

Apa pun di .Net yang dapat Anda ulangi dari implementasinya IEnumerable. Jika Anda membangun kelas Anda sendiri, dan itu belum mewarisi dari kelas yang mengimplementasikan IEnumerable, Anda dapat membuat kelas Anda dapat digunakan dalam foreachpernyataan dengan menerapkan IEnumerable(dan dengan membuat kelas enumerator bahwa GetEnumeratormetode baru akan kembali).


15
Saya pikir ketika poster asli mengatakan "over foreach", maksudnya "kapan saya harus memanggil GetEnumerator () / MoveNext () secara eksplisit daripada menggunakan loop foreach." Untuk apa nilainya.
mqp

6
Ah, saya pikir Anda benar. Yah, jawabannya tersirat dalam posting saya: tidak masalah, karena itulah yang dilakukan kompiler. Jadi lakukan yang termudah, yaitu gunakan foreach.
Robert Rossney

12
Jawaban ini tidak menceritakan keseluruhan cerita. Objek yang dapat dihitung tidak perlu mengimplementasikan IEnumerable; mereka hanya perlu memiliki metode GetEnumerator yang mengembalikan turunan tipe yang pada gilirannya memiliki bool MoveNext()metode dan Currentproperti tipe apa pun. Pendekatan "mengetik bebek" ini diterapkan di C # 1.0 sebagai cara untuk menghindari tinju ketika menghitung koleksi tipe nilai.
phoog

3
Dengan perluasan dari atas dan bekerja melalui Workthrough: Menerapkan IEnumerable of (T) Anda memiliki sumber greate.
ruedi

4
Apakah ini seperti C ++ iterator?
Matt G

161

Antarmuka IEnumerable dan IEnumerator

Untuk mulai memeriksa proses penerapan antarmuka .NET yang ada, mari kita lihat peran IEnumerable dan IEnumerator. Ingatlah bahwa C # mendukung kata kunci bernama foreach yang memungkinkan Anda untuk mengulangi isi dari jenis array apa pun:

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

Meskipun mungkin terlihat bahwa hanya tipe array yang dapat menggunakan konstruk ini, kebenaran dari masalahnya adalah semua tipe yang mendukung metode bernama GetEnumerator () dapat dievaluasi oleh konstruk foreach. Untuk menggambarkan, ikuti saya!

Misalkan kita memiliki kelas Garasi:

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

Idealnya, akan lebih mudah untuk beralih di atas subtitle objek Garage menggunakan konstruksi foreach, seperti array nilai data:

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

Sayangnya, kompiler memberi tahu Anda bahwa kelas Garage tidak mengimplementasikan metode bernama GetEnumerator (). Metode ini diformalkan oleh antarmuka IEnumerable, yang ditemukan bersembunyi di dalam namespace System.Collections. Kelas atau struktur yang mendukung perilaku ini mengiklankan bahwa mereka dapat mengekspos subitem yang terkandung ke pemanggil (dalam contoh ini, kata kunci foreach itu sendiri). Berikut adalah definisi antarmuka .NET standar ini:

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

Seperti yang Anda lihat, metode GetEnumerator () mengembalikan referensi ke antarmuka lain bernama System.Collections.IEnumerator. Antarmuka ini menyediakan infrastruktur untuk memungkinkan pemanggil melintasi objek internal yang terkandung oleh wadah yang kompatibel dengan 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.
}

Jika Anda ingin memperbarui tipe Garage untuk mendukung antarmuka ini, Anda bisa menempuh jalan panjang dan mengimplementasikan setiap metode secara manual. Meskipun Anda tentu saja bebas untuk menyediakan versi GetEnumerator (), MoveNext (), Current, dan Reset () yang disesuaikan, ada cara yang lebih sederhana. Karena tipe System.Array (dan juga banyak kelas koleksi lainnya) sudah mengimplementasikan IEnumerable dan IEnumerator, Anda bisa mendelegasikan permintaan ke System.Array sebagai berikut:

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

Setelah Anda memperbarui tipe Garage, Anda dapat menggunakan tipe itu dengan aman di dalam konstruksi C # foreach. Selanjutnya, mengingat bahwa metode GetEnumerator () telah didefinisikan secara publik, pengguna objek juga dapat berinteraksi dengan tipe 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);

Namun, jika Anda lebih suka menyembunyikan fungsi IEnumerable dari tingkat objek, cukup gunakan implementasi antarmuka eksplisit:

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

Dengan melakukannya, pengguna objek biasa tidak akan menemukan metode GetEnumerator () Garage, sedangkan konstruksi foreach akan mendapatkan antarmuka di latar belakang bila diperlukan.

Diadaptasi dari Pro C # 5.0 dan .NET 4.5 Framework


1
Jawaban yang fantastis, terima kasih! Saya punya satu pertanyaan. Pada contoh pertama Anda mengulangi array menggunakan foreach tapi kemudian Anda tidak bisa melakukannya dalam contoh kedua. Apakah ini karena array berada dalam kelas atau karena mengandung objek?
Caleb Palmquist

Terima kasih atas penjelasannya. Satu-satunya pertanyaan saya adalah mengapa tidak hanya memiliki metode Garageyang didapat carArray? Dengan begitu Anda tidak perlu menerapkan GetEnumeratorsendiri, karena Arraysudah melakukan ini. Misalnyaforeach(Car c in carLot.getCars()) { ... }
Nick Rolando

63

Menerapkan IEnumerable berarti kelas Anda mengembalikan objek IEnumerator:

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

Menerapkan IEnumerator berarti kelas Anda mengembalikan metode dan properti untuk iterasi:

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

    public bool MoveNext()...

    public object Current...
}

Itulah bedanya.


1
Bagus, ini menjelaskan (bersama dengan posting lain) bagaimana mengkonversi kelas Anda menjadi satu yang dapat Anda gunakan "foreach" untuk beralih pada isinya.
Contango

54

Penjelasan melalui Analogi + Panduan Kode

Pertama, penjelasan tanpa kode, lalu saya tambahkan nanti.

Katakanlah Anda menjalankan perusahaan penerbangan. Dan di setiap pesawat Anda ingin mengetahui informasi tentang penumpang yang terbang di pesawat. Pada dasarnya Anda ingin dapat "melintasi" pesawat. Dengan kata lain, Anda ingin dapat mulai di kursi depan, dan kemudian berjalan ke bagian belakang pesawat, menanyakan beberapa penumpang informasi: siapa mereka, dari mana mereka berasal dll. Pesawat terbang hanya dapat melakukan ini , jika memang:

  1. dihitung, dan
  2. jika memiliki penghitung.

Mengapa persyaratan ini? Karena itulah yang diperlukan antarmuka.

Jika ini adalah informasi yang berlebihan, yang perlu Anda ketahui adalah bahwa Anda ingin dapat mengajukan beberapa pertanyaan kepada setiap penumpang di pesawat, mulai dari yang pertama dan berjalan ke yang terakhir.

Apa artinya dihitung?

Jika sebuah maskapai penerbangan "dapat dihitung", ini berarti bahwa HARUS ada pramugari yang hadir di pesawat, yang tugas satu-satunya adalah menghitung - dan pramugari ini HARUS menghitung dengan cara yang sangat spesifik:

  1. Konter / pramugari HARUS memulai sebelum penumpang pertama (di depan semua orang di mana mereka mendemonstrasikan keselamatan, cara mengenakan jaket pelampung dll).
  2. Dia (yaitu pramugari) HARUS "bergerak berikutnya" di lorong ke kursi pertama.
  3. Dia kemudian mencatat: (i) siapa orang yang ada di kursi, dan (ii) lokasi mereka saat ini di lorong.

Prosedur Penghitungan

Kapten maskapai menginginkan laporan tentang setiap penumpang ketika dan ketika mereka diselidiki atau dihitung. Jadi setelah berbicara dengan orang yang duduk di kursi pertama, pramugari / konter kemudian melapor kepada kapten, dan ketika laporan diberikan, konter mengingat posisi tepatnya di lorong dan terus menghitung tepat di mana dia pergi mati.

Dengan cara ini kapten selalu dapat memiliki informasi tentang orang yang sedang diselidiki. Dengan begitu, jika dia mengetahui bahwa orang ini menyukai Manchester City, maka dia dapat memberikan perlakuan istimewa pada penumpang tersebut, dll.

  • Penghitung terus berjalan sampai dia mencapai ujung pesawat.

Mari kita ikat ini dengan IEnumerables

  • Seorang enumerable hanyalah kumpulan penumpang di pesawat. Hukum Penerbangan Sipil - ini pada dasarnya adalah aturan yang harus diikuti oleh semua jumlah IEnumerable. Setiap kali pramugari pergi ke kapten dengan informasi penumpang, kami pada dasarnya 'menyerahkan' penumpang ke kapten. Kapten pada dasarnya dapat melakukan apapun yang dia inginkan dengan penumpang - kecuali mengatur ulang penumpang di pesawat. Dalam hal ini, mereka diberikan perlakuan istimewa jika mereka mengikuti Manchester City (ugh!)

    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)
    

Ringkasan

Dengan kata lain, sesuatu dapat diperhitungkan jika memiliki penghitung . Dan kontra keharusan (pada dasarnya): (i) ingat tempatnya ( state ), (ii) dapat bergerak ke depan , (iii) dan tahu tentang saat orang yang ia berurusan dengan.

Enumerable hanyalah sebuah kata mewah untuk "countable". Dengan kata lain, enumerable memungkinkan Anda untuk 'menghitung' (yaitu menghitung).


23

IEnumerable mengimplementasikan GetEnumerator. Ketika dipanggil, metode itu akan mengembalikan IEnumerator yang mengimplementasikan MoveNext, Reset dan Current.

Jadi ketika kelas Anda mengimplementasikan IEnumerable, Anda mengatakan bahwa Anda dapat memanggil metode (GetEnumerator) dan mendapatkan objek baru yang dikembalikan (sebuah IEnumerator) yang dapat Anda gunakan dalam satu loop seperti foreach.


18

Menerapkan IEnumerable memungkinkan Anda untuk mendapatkan IEnumerator untuk daftar.

IEnumerator memungkinkan akses berurutan gaya foreach ke item dalam daftar, menggunakan kata kunci hasil.

Sebelum implementasi foreach (di Java 1.4, misalnya), cara untuk mengulang daftar adalah untuk mendapatkan enumerator dari daftar, kemudian meminta item "berikutnya" dalam daftar, selama nilai dikembalikan sebagai yang berikutnya item bukan nol. Foreach hanya melakukan itu secara implisit sebagai fitur bahasa, dengan cara yang sama yang mengunci () mengimplementasikan kelas Monitor di belakang layar.

Saya berharap foreach bekerja pada daftar karena mereka mengimplementasikan IEnumerable.


jika itu untuk daftar mengapa saya tidak bisa menggunakan foreach saja?
prodev42

.Net duck mengetikkan pernyataan foreach, tetapi IEnumerable / IEnumerable <T> adalah cara yang tepat untuk mengatakan bahwa kelas Anda dapat disebutkan.
user7116

15
  • Objek yang mengimplementasikan IEnumerable memungkinkan orang lain mengunjungi setiap itemnya (oleh enumerator) .
  • Objek yang mengimplementasikan IEnumerator adalah yang melakukan iterasi. Itu berulang di atas objek enumerable.

Pikirkan benda yang bisa dihitung sebagai daftar, tumpukan, pohon.


12

IEnumerable dan IEnumerator (dan rekan-rekan generik mereka IEnumerable <T> dan IEnumerator <T>) adalah antarmuka dasar dari implementasi iterator di koleksi .Net Framework Class Libray .

IEnumerable adalah antarmuka paling umum yang akan Anda lihat di sebagian besar kode di luar sana. Ini memungkinkan foreach loop, generator (think yield ) dan karena antarmuka yang kecil, ini digunakan untuk membuat abstraksi yang ketat. IEnumerable tergantung pada IEnumerator .

IEnumerator , di sisi lain, menyediakan antarmuka iterasi yang sedikit lebih rendah. Ini disebut sebagai iterator eksplisit yang memberi programmer lebih banyak kontrol atas siklus iterasi.

Tidak terhitung

IEnumerable adalah antarmuka standar yang memungkinkan pengulangan koleksi yang mendukungnya (pada kenyataannya, semua jenis koleksi yang dapat saya pikirkan saat ini mengimplementasikan IEnumerable ). Dukungan kompiler memungkinkan fitur bahasa seperti foreach. Secara umum, ini memungkinkan implementasi iterator implisit ini .

foreach Loop

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

Saya pikir foreachloop adalah salah satu alasan utama untuk menggunakan antarmuka IEnumerable . foreachmemiliki sintaksis yang sangat ringkas dan sangat mudah dipahami dibandingkan dengan gaya C klasik untuk loop di mana Anda perlu memeriksa berbagai variabel untuk melihat apa yang dilakukannya.

menghasilkan kata kunci

Mungkin fitur yang kurang diketahui adalah bahwa IEnumerable juga memungkinkan generator di C # dengan penggunaan yield returndan yield breakpernyataan.

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

Abstraksi

Skenario umum lainnya dalam praktik adalah menggunakan IEnumerable untuk memberikan abstraksi minimalis. Karena itu adalah antarmuka sangat kecil dan hanya-baca, Anda didorong untuk mengekspos koleksi Anda sebagai IEnumerable (bukan List misalnya). Dengan begitu Anda bebas untuk mengubah implementasi Anda tanpa melanggar kode klien Anda (misalnya, ubah Daftar ke LinkedList ).

Kena kau

Satu perilaku yang harus diperhatikan adalah bahwa dalam implementasi streaming (mis. Mengambil data baris demi baris dari database, alih-alih memuat semua hasil dalam memori terlebih dahulu) Anda tidak dapat mengulangi koleksi lebih dari sekali. Ini berbeda dengan koleksi dalam memori seperti Daftar , di mana Anda dapat mengulangi beberapa kali tanpa masalah. ReSharper, misalnya, memiliki inspeksi kode untuk kemungkinan enumerasi ganda dari IEnumerable .

IEnumerator

IEnumerator, di sisi lain, adalah antarmuka di belakang layar yang membuat IEnumerble-foreach-magic bekerja. Sebenarnya, ini memungkinkan iterator eksplisit.

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

Dalam pengalaman saya, IEnumerator jarang digunakan dalam skenario umum karena sintaksisnya lebih verbose dan semantik yang sedikit membingungkan (setidaknya bagi saya; eg MoveNext () mengembalikan nilai juga, yang namanya tidak disarankan sama sekali).

Gunakan case untuk IEnumerator

Saya hanya menggunakan IEnumerator di perpustakaan (kerangka yang sedikit lebih rendah) dan kerangka kerja di mana saya menyediakan antarmuka IEnumerable . Salah satu contoh adalah pustaka pemrosesan aliran data yang menyediakan serangkaian objek dalam satu foreachlingkaran meskipun di balik layar data dikumpulkan menggunakan berbagai aliran file dan serialisasi.

Kode klien

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

Perpustakaan

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

Menerapkan IEnumerablepada dasarnya berarti bahwa objek dapat diulangi. Ini tidak selalu berarti array karena ada daftar tertentu yang tidak dapat diindeks tetapi Anda dapat menghitungnya.

IEnumeratoradalah objek aktual yang digunakan untuk melakukan iterasi. Ini mengontrol bergerak dari satu objek ke yang berikutnya dalam daftar.

Sebagian besar waktu, IEnumerable& IEnumeratordigunakan secara transparan sebagai bagian dari foreachloop.


6

Perbedaan antara IEnumerable dan IEnumerator:

  • IEnumerable menggunakan IEnumerator secara internal.
  • IEnumerable tidak tahu item / objek mana yang dieksekusi.
  • Setiap kali kita melewati IEnumerator ke fungsi lain, ia mengetahui posisi item / objek saat ini.
  • Setiap kali kami meneruskan koleksi IEnumerable ke fungsi lain, ia tidak tahu posisi item / objek saat ini (tidak tahu item mana yang dieksekusi)

    IEnumerable memiliki satu metode GetEnumerator ()

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

IEnumerator memiliki satu properti yang disebut Current dan dua metode, Reset () dan MoveNext () (yang berguna untuk mengetahui posisi item saat ini dalam daftar).

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

5

IEnumerable adalah kotak yang berisi Ienumerator. IEnumerable adalah antarmuka dasar untuk semua koleksi. foreach loop dapat beroperasi jika koleksi mengimplementasikan IEnumerable. Dalam kode di bawah ini menjelaskan langkah memiliki Enumerator kita sendiri. Pertama-tama mari kita tentukan Kelas kita yang akan kita buat koleksi.

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

Sekarang kita akan mendefinisikan Kelas yang akan bertindak sebagai koleksi untuk Pelanggan kelas kita. Perhatikan bahwa itu mengimplementasikan antarmuka IEnumerable. Sehingga kita harus mengimplementasikan metode GetEnumerator. Ini akan mengembalikan Enumerator khusus kami.

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

Sekarang kita akan membuat Enumerator khusus kita sendiri sebagai berikut. Jadi, kita harus mengimplementasikan metode 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.
        }
    }

Sekarang kita bisa menggunakan foreach loop pada koleksi kita seperti di bawah ini;

    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

Pemahaman tentang pola Iterator akan membantu Anda. Saya sarankan membaca yang sama.

Pola Iterator

Pada tingkat tinggi, pola iterator dapat digunakan untuk memberikan cara pengulangan standar melalui koleksi jenis apa pun. Kami memiliki 3 peserta dalam pola iterator, koleksi aktual (klien), agregator dan iterator. Agregat adalah kelas antarmuka / abstrak yang memiliki metode yang mengembalikan iterator. Iterator adalah kelas antarmuka / abstrak yang memiliki metode yang memungkinkan kita untuk beralih melalui koleksi.

Untuk menerapkan pola pertama-tama kita perlu menerapkan iterator untuk menghasilkan beton yang dapat diulang atas koleksi yang bersangkutan (klien). Kemudian koleksi (klien) mengimplementasikan agregator untuk mengembalikan instance dari iterator di atas.

Berikut adalah diagram UML Pola Iterator

Jadi pada dasarnya dalam c #, IEnumerable adalah agregat abstrak dan IEnumerator adalah Iterator abstrak. IEnumerable memiliki metode tunggal GetEnumerator yang bertanggung jawab untuk membuat instance IEnumerator dari tipe yang diinginkan. Koleksi seperti Daftar menerapkan IEnumerable.

Contoh. Mari kita anggap kita memiliki metode getPermutations(inputString)yang mengembalikan semua permutasi string dan metode mengembalikan contohIEnumerable<string>

Untuk menghitung jumlah permutasi, kita dapat melakukan sesuatu seperti di bawah ini.

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

Kompiler c # kurang lebih mengubah konversi di atas menjadi

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

Jika Anda memiliki pertanyaan, jangan ragu untuk bertanya.


2

Kontribusi minor.

Seperti banyak dari mereka menjelaskan tentang 'kapan harus menggunakan' dan 'gunakan dengan foreach'. Saya berpikir untuk menambahkan Perbedaan Negara Lain di sini seperti yang diminta dalam pertanyaan tentang perbedaan antara kedua IEnumerable dan IEnumerator.

Saya membuat contoh kode di bawah ini berdasarkan utas diskusi di bawah ini.

IEnumerable, IEnumerator vs foreach, kapan harus menggunakan apa perbedaan antara IEnumerator dan IEnumerable?

Enumerator mempertahankan status (posisi iterasi) antara panggilan fungsi sementara iterasi sebaliknya Enumerable tidak.

Berikut adalah contoh yang diuji dengan komentar untuk dipahami.

Para ahli harap tambahkan / koreksi saya.

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

Saya perhatikan perbedaan-perbedaan ini:

A. Kita mengulang daftar dengan cara yang berbeda, foreach dapat digunakan untuk IEnumerable dan while loop untuk IEnumerator.

B. IEnumerator dapat mengingat indeks saat ini ketika kami beralih dari satu metode ke metode lain (ini mulai bekerja dengan indeks saat ini) tetapi IEnumerable tidak dapat mengingat indeks dan mereset indeks ke awal. Lebih banyak di video ini https://www.youtube.com/watch?v=jd3yUjGc9M0


1

IEnumerabledan IEnumeratorkeduanya adalah antarmuka dalam C #.

IEnumerableadalah antarmuka yang mendefinisikan metode tunggal GetEnumerator()yang mengembalikan IEnumeratorantarmuka.

Ini berfungsi untuk akses hanya baca ke koleksi yang mengimplementasikan yang IEnumerabledapat digunakan dengan foreachpernyataan.

IEnumeratormemiliki dua metode, MoveNextdan Reset. Ini juga memiliki properti yang disebut Current.

Berikut ini menunjukkan implementasi IEnumerable dan 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
  */
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.