IEnumerable ve IEnumerator'ı bana açıklayan var mı? [kapalı]


272

IEnumerable ve IEnumerator'ı bana açıklayan var mı?

örneğin, ne zaman foreach üzerinde kullanılır? IEnumerable ve IEnumerator arasındaki fark nedir? Neden kullanmamız gerekiyor?


55
Bu Java ve JavaScript'ten bu yana en kötü adlandırma karışımı
Matthew Lock

@MatthewLock ne demek istediğini açıklayabilir misin?
David Klempfner

Yanıtlar:


275

örneğin, ne zaman foreach üzerinde kullanılır?

IEnumerable"Üzerinden" kullanmazsınız foreach. Uygulamayı IEnumerablekullanmayı foreach mümkün kılar .

Gibi bir kod yazdığınızda:

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

işlevsel olarak yazmaya eşittir:

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

"İşlevsel olarak eşdeğer" derken, derleyici kodu dönüştüren şey budur. Sen kullanamazsınız foreachüzerinde bazbu örnekte sürece baz uygular IEnumerable.

IEnumerablebazyöntemi uygulayan anlamına gelir

IEnumerator GetEnumerator()

IEnumeratorBu yöntem döndürür yöntemleri uygulamak gerekir ki nesne

bool MoveNext()

ve

Object Current()

İlk yöntem IEnumerablenumaralandırıcıyı yaratan nesnede bir sonraki nesneye ilerler , falseeğer yapılırsa geri döner ve ikincisi geçerli nesneyi döndürür.

.Net üzerinde herhangi bir şey üzerinden yineleme yapabilirsiniz uygular IEnumerable. Kendi sınıfınızı oluşturuyorsanız ve zaten uygulayan bir sınıftan miras almıyorsanız IEnumerable, foreachuygulayarak IEnumerable(ve yeni GetEnumeratoryönteminin döndüreceği bir numaralandırıcı sınıfı oluşturarak) sınıfınızı ifadelerde kullanılabilir hale getirebilirsiniz .


15
Bence orijinal poster "overeach" dediğinde, "ne zaman açık foreach döngü kullanmak yerine GetEnumerator () / MoveNext () çağırmalı." Değer için.
mqp

6
Ah, bence haklısın. Cevabın yazımdaki üstü kapalı: önemli değil, çünkü derleyicinin zaten yaptığı şey bu. En kolay olanı yapın, yani foreach kullanın.
Robert Rossney

12
Bu cevap hikayenin tamamını anlatmaz. Numaralandırılabilir nesnelerin IEnumerable uygulamasına gerek yoktur; yalnızca, bir bool MoveNext()yönteme ve Currentherhangi bir tür özelliğine sahip bir tür örneğini döndüren bir GetEnumerator yöntemine sahip olmaları gerekir . Bu "ördek tipleme" yaklaşımı, C # 1.0'da, değer türü koleksiyonları numaralandırırken boksu önlemenin bir yolu olarak uygulanmıştır.
phoog

3
Yukarıdaki açıklama ve Workthrough: IEnumerable (T) uygulamak ile greate kaynakları var.
ruedi

4
Bu tür bir C ++ gibi iteratormi?
Matt G

161

IEnumerable ve IEnumerator Arabirimleri

Mevcut .NET arabirimlerini uygulama sürecini incelemeye başlamak için, önce IEnumerable ve IEnumerator rolüne bakalım. C # 'ın, herhangi bir dizi türünün içeriğini yinelemenize izin veren foreach adlı bir anahtar kelimeyi desteklediğini hatırlayın:

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

Bu yapıdan sadece dizi türlerinin faydalanabileceği görünse de, konunun gerçeği, GetEnumerator () adında bir yöntemi destekleyen herhangi bir türdür, foreach yapısı tarafından değerlendirilebilir.

Bir Garaj sınıfımız olduğunu varsayalım:

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

İdeal olarak, tıpkı bir veri değerleri dizisi gibi, foreach yapısını kullanarak Garaj nesnesinin alt öğelerini yinelemek uygun olacaktır:

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

Ne yazık ki derleyici, Garage sınıfının GetEnumerator () adında bir yöntem uygulamadığını bildirir. Bu yöntem, System.Collections ad alanında gizlenen IEnumerable arabirimi tarafından resmileştirilmiştir. Bu davranışı destekleyen sınıflar veya yapılar, içerilen alt öğeleri arayana gösterebileceklerini bildirir (bu örnekte foreach anahtar sözcüğünün kendisi). İşte bu standart .NET arabiriminin tanımı:

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

Gördüğünüz gibi GetEnumerator () yöntemi, System.Collections.IEnumerator adlı başka bir arabirime başvuru döndürür. Bu arabirim, arayanın IEnumerable uyumlu kapsayıcıda bulunan dahili nesneleri geçmesine izin verecek altyapıyı sağlar:

// 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.
}

Garaj türünü bu arayüzleri destekleyecek şekilde güncellemek istiyorsanız, uzun yoldan gidebilir ve her yöntemi manuel olarak uygulayabilirsiniz. GetEnumerator (), MoveNext (), Current ve Reset () 'in özelleştirilmiş sürümlerini sağlamakta özgürsünüz, ancak daha basit bir yol var. System.Array türü (ve diğer birçok koleksiyon sınıfının yanı sıra) zaten IEnumerable ve IEnumerator uyguladığından, isteği System.Array öğesine aşağıdaki şekilde atayabilirsiniz:

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

Garaj türünüzü güncelledikten sonra, C # foreach yapısı içindeki türü güvenle kullanabilirsiniz. Ayrıca, GetEnumerator () yönteminin genel olarak tanımlandığı göz önüne alındığında, nesne kullanıcısı IEnumerator türüyle de etkileşime girebilir:

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

Ancak, IEnumerable işlevini nesne düzeyinden gizlemeyi tercih ediyorsanız, açık arabirim uygulamasını kullanın:

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

Bu şekilde, geçici nesne kullanıcısı Garage'ın GetEnumerator () yöntemini bulamazken, foreach yapısı gerektiğinde arka planda arabirimi elde eder.

Pro C # 5.0 ve .NET 4.5 Framework'ten uyarlanmıştır


1
Harika cevap, teşekkür ederim! Fakat bir sorum var. İlk örnekte foreach kullanarak dizi üzerinde döngü yaparsınız, ancak ikinci örnekte bunu yapamazsınız. Bunun nedeni dizi bir sınıfta mı yoksa nesne içerdiği için mi?
Caleb Palmquist

Harika açıklama için teşekkürler. Benim tek sorum neden sadece bir yöntem var olsun Garageki carArray? Bu şekilde GetEnumeratorkendinizi uygulamak zorunda değilsiniz , çünkü bunu Arrayzaten yapıyor. Örn.foreach(Car c in carLot.getCars()) { ... }
Nick Rolando

63

IEnumerable uygulamak, sınıfınızın bir IEnumerator nesnesi döndürdüğü anlamına gelir:

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

IEnumerator uygulaması, sınıfınızın yineleme için yöntemleri ve özellikleri döndüreceği anlamına gelir:

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

    public bool MoveNext()...

    public object Current...
}

Zaten fark bu.


1
Güzel, bu, (diğer yayınlarla birlikte), sınıfınızı, içeriğini yinelemek için "foreach" kullanabileceğiniz bir sınıfa nasıl dönüştüreceğinizi açıklar.
Contango

54

Analogy + Kod İzlenecek Yol ile Açıklama

Önce kodsuz bir açıklama, daha sonra ekleyeceğim.

Diyelim ki bir havayolu şirketi işletiyorsunuz. Ve her düzlemde, uçakta uçan yolcular hakkında bilgi edinmek istersiniz. Temel olarak uçağı "hareket ettirmek" istersiniz. Başka bir deyişle, ön koltukta başlayabilmek ve daha sonra uçağın arkasına doğru ilerlemek, yolculara bazı bilgiler sorabilmek istiyorsunuz: kim olduklarını, nereden geldiklerini vb. Bir uçak sadece bunu yapabilir , Öyleyse:

  1. sayılabilir ve
  2. bir sayacı varsa.

Neden bu gereksinimler? Çünkü arayüzün gerektirdiği şey bu.

Bu aşırı bilgi yükü ise, bilmeniz gereken tek şey, uçaktaki her yolcuya ilkinden başlayarak sonuncuya doğru yol almak için bazı sorular sormak isteyebileceğinizdir.

Sayılabilir ne demektir?

Bir havayolu "sayılabilir" ise, bu, uçakta mevcut olan bir uçuş görevlisi olması gerektiği anlamına gelir, tek işi saymaktır - ve bu uçuş görevlisi çok özel bir şekilde saymak GEREKİR:

  1. Karşı / uçuş görevlisi ilk yolcudan önce BAŞLATILMALIDIR (demo güvenliğinin olduğu herkesin önünde, can yeleğinin nasıl giyileceği vb.).
  2. O (yani uçuş görevlisi) koridorda ilk koltuğa "bir sonraki" hareket ZORUNDADIR.
  3. Daha sonra şunları kaydedecektir: (i) kişinin koltukta kim olduğu ve (ii) koridordaki mevcut yeri.

Sayma Prosedürleri

Havayolu kaptanı, soruşturulduğu veya sayılacağı zaman her yolcu hakkında bir rapor istiyor. Böylece birinci koltuktaki kişiyle konuştuktan sonra, uçuş görevlisi / sayaç kaptana rapor verir ve rapor verildiğinde, sayaç koridordaki tam konumunu hatırlar ve kaldığı yerden saymaya devam eder kapatır.

Bu şekilde kaptan, araştırılmakta olan kişi hakkında her zaman bilgi sahibi olur. Bu şekilde, bu bireyin Manchester City'yi sevdiğini öğrenirse, o yolcuya tercihli muamele vb. Verebilir.

  • Sayaç uçağın sonuna ulaşana kadar devam eder.

Bunu IEnumerables ile bağlayalım

  • Bir numaralandırılabilir sadece bir uçakta yolcuların bir koleksiyon. Sivil Havacılık Kanunu - bunlar temel olarak tüm IEnumerable'ların uyması gereken kurallardır. Havayolu görevlisi passeger bilgileriyle kaptana her gittiğinde, temelde yolcuyu kaptana 'veriyoruz'. Kaptan temel olarak yolcu ile istediği her şeyi yapabilir - uçaktaki yolcuları yeniden düzenlemek dışında. Bu durumda, Manchester City'yi izlerse onlara tercihli tedavi verilir (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)
    

özet

Başka bir deyişle, bir sayacı varsa bir şey sayılabilir . Ve sayaç (temel olarak): (i) yerini ( durumunu ) hatırlar , (ii) bir sonraki adımda hareket edebilir , (iii) ve uğraştığı şu anki kişiyi bilir .

Enumerable sadece "sayılabilir" için süslü bir kelime. Başka bir deyişle, bir numaralandırılabilir 'numaralandırmanıza (yani saymanıza) izin verir.


23

IEnumerable GetEnumerator uygular. Bu yöntem çağrıldığında MoveNext, Reset ve Current uygulayan bir IEnumerator döndürür .

Böylece sınıfınız IEnumerable uyguladığında, bir yöntemi (GetEnumerator) çağırabileceğinizi ve foreach gibi bir döngüde kullanabileceğiniz yeni bir nesne (IEnumerator) döndüğünüzü söylersiniz.


18

IEnumerable uygulaması, bir liste için bir IEnumerator almanızı sağlar.

IEnumerator, verim anahtar sözcüğünü kullanarak listedeki öğelere her biçime sıralı erişime izin verir.

Her uygulamadan önce (örneğin Java 1.4'te), bir listeyi yinelemenin yolu listeden bir numaralandırıcı almak ve ardından bir sonraki gibi döndürülen değer olduğu sürece listeden "sonraki" öğeyi istemektir. öğe boş değil. Foreach bunu bunu bir dil özelliği olarak, lock () öğesinin perde sınıfının arkasına uyguladığı şekilde yapar.

IEnumerable uyguladıkları için listelerde foreach çalışmaları bekliyorum.


bir liste için neden sadece foreach kullanamıyorum?
prodev42

Net duck, foreach deyimini yazar, ancak IEnumerable / IEnumerable <T>, sınıfınızın numaralandırılabileceğini söylemenin uygun yoludur.
user7116

15
  • IEnumerable uygulayan bir nesne , diğerlerinin öğelerinin her birini (bir numaralandırıcı tarafından) ziyaret etmesine izin verir .
  • IEnumerator uygulayan bir nesne yinelemedir. Numaralandırılabilir bir nesnenin üzerinde dönüyor.

Numaralandırılabilir nesneleri listeler, yığınlar, ağaçlar olarak düşünün.


12

IEnumerable ve IEnumerator (ve genel benzerleri IEnumerable <T> ve IEnumerator <T>) .Net Framework Sınıfı Libray koleksiyonlarındaki yineleyici uygulamalarının temel arabirimleridir .

IEnumerable , kodun çoğunda gördüğünüz en yaygın arabirimdir. Foreach döngüsünü, jeneratörleri (düşünen verim ) sağlar ve küçük arayüzü nedeniyle sıkı soyutlamalar oluşturmak için kullanılır. IEnumerable, IEnumerator'a bağlıdır .

IEnumerator , diğer taraftan, biraz daha düşük seviyeli bir yineleme arabirimi sağlar. Programcıya yineleme döngüsü üzerinde daha fazla kontrol sağlayan açık yineleyici olarak adlandırılır .

IEnumerable

IEnumerable, onu destekleyen koleksiyonlar üzerinde yinelemeyi sağlayan standart bir arabirimdir (aslında, bugün aklıma gelen tüm koleksiyon türleri IEnumerable uygular ). Derleyici desteği gibi dil özelliklerine izin verir foreach. Genel olarak, bu örtük yineleyici uygulamasını mümkün kılar .

foreach Döngüsü

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

foreachDöngü IEnumerable arabirimlerini kullanmanın ana nedenlerinden biri olduğunu düşünüyorum . foreachçok değişken bir sözdizimine sahiptir ve ne yaptığını görmek için çeşitli değişkenleri kontrol etmeniz gereken döngüler için klasik C stiline kıyasla anlaşılması çok kolaydır .

Anahtar Kelime

Muhtemelen daha az bilinen bir özellik, IEnumerable'ın C # 'daki jeneratörlerinyield return ve yield breakifadelerinin kullanımı ile etkinleştirilmesidir .

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

Soyutlamalar

Uygulamadaki bir diğer yaygın senaryo, minimalist soyutlamalar sağlamak için IEnumerable kullanmaktır . Küçük ve salt okunur bir arayüz olduğundan, koleksiyonlarınızı IEnumerable olarak ( örneğin Liste yerine) göstermeniz önerilir . Bu şekilde, müşterinizin kodunu kırmadan uygulamanızı değiştirebilirsiniz ( örneğin Listeyi bir LinkedList olarak değiştirin ).

Anladım

Bir davranış (örneğin bir veritabanından satırda veri satırı almak yerine öncelikle hafızada sonucu yüklenirken) akışı uygulamalarda olmasıdır Dikkat edilmesi gereken olamaz yinelerler kereden fazla koleksiyonu üzerinde. Bu, List gibi bellekte olmayan koleksiyonların aksine , sorunsuz bir şekilde birden çok kez yineleyebileceğiniz. Örneğin ReSharper, olası IEnumerable çoklu numaralandırması için bir kod denetimine sahiptir .

IEnumerator

IEnumerator, diğer taraftan, IEnumerble-foreach-magic çalışmasını sağlayan sahne arkası arabirimidir . Açık konuşmak gerekirse, açık yineleyiciler sağlar.

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

Deneyimlerime göre IEnumerator , daha ayrıntılı sözdizimi ve biraz kafa karıştırıcı anlambiliminden dolayı yaygın senaryolarda nadiren kullanılır (en azından benim için; örneğin MoveNext () , adın hiç önermediği bir değer de döndürür).

IEnumerator için kullanım örneği

Yalnızca IEnumerator'ı ( IEnumerable arabirimleri sağladığım) özellikle (biraz daha düşük düzeyde) kitaplıklar ve çerçeveler kullandım . Bir örnek, foreachsahne arkasındaki veriler çeşitli dosya akışları ve serileştirmeler kullanılarak toplansa da , bir döngü içinde bir dizi nesne sağlayan bir veri akışı işleme kütüphanesidir .

Müşteri kodu

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

Kütüphane

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

Gerçekte uygulama IEnumerable, nesnenin tekrarlanabileceği anlamına gelir. Bu, dizine eklenemeyen belirli listeler olduğu için bir dizi olduğu anlamına gelmez, ancak bunları numaralandırabilirsiniz.

IEnumeratoryinelemeleri gerçekleştirmek için kullanılan gerçek nesnedir. Listedeki bir nesneden diğerine geçmeyi kontrol eder.

Çoğu zaman, IEnumerable& IEnumeratorbir foreachdöngünün parçası olarak şeffaf bir şekilde kullanılır .


6

IEnumerable ve IEnumerator arasındaki farklar:

  • IEnumerable dahili olarak IEnumerator kullanır.
  • IEnumerable hangi öğenin / nesnenin yürütüldüğünü bilmiyor.
  • IEnumerator'ı başka bir işleve geçirdiğimizde, öğenin / nesnenin geçerli konumunu bilir.
  • IEnumerable koleksiyonunu başka bir işleve geçirdiğimizde, öğenin / nesnenin geçerli konumunu bilmiyor (hangi öğeyi yürüttüğünü bilmiyor)

    IEnumerable bir yöntem GetEnumerator () var

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

IEnumerator, Current adlı iki özelliğe ve Reset () ve MoveNext () yöntemine sahiptir (bu, listedeki bir öğenin geçerli konumunu bilmek için yararlıdır).

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

5

IEnumerable, Ienumerator içeren bir kutudur. IEnumerable tüm koleksiyonlar için temel arayüzdür. toplama IEnumerable uygularsa foreach döngüsü çalışabilir. Aşağıdaki kodda, kendi Numaralandırıcıya sahip olma adımını açıklar. İlk olarak koleksiyonunu yapacağımız Sınıfımızı tanımlayalım.

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

Şimdi Sınıf Müşterimiz için bir koleksiyon görevi görecek olan Sınıfı tanımlayacağız. IEnumerable arabirimini uyguladığına dikkat edin. Böylece GetEnumerator yöntemini uygulamak zorundayız. Bu, özel Numaralandırıcımızı döndürecektir.

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

Şimdi aşağıdaki gibi kendi özel Sayımcımızı oluşturacağız. Bu nedenle, MoveNext yöntemini uygulamalıyız.

 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.
        }
    }

Şimdi foreach döngüsünü koleksiyonumuz üzerinde aşağıdaki gibi kullanabiliriz;

    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

Yineleyici modelini anlamak sizin için yararlı olacaktır. Ben de aynısını okumanızı tavsiye ederim.

Yineleyici Desen

Yüksek seviyede yineleyici deseni, herhangi bir tipteki koleksiyonlar yoluyla standart bir yineleme yöntemi sağlamak için kullanılabilir. Yineleyici modelinde, gerçek koleksiyonda (istemci), toplayıcıda ve yineleyicide 3 katılımcı var. Toplama, yineleyici döndüren bir yöntemi olan bir arabirim / soyut sınıftır. Yineleyici, bir koleksiyon üzerinden yineleme yapmamıza izin veren yöntemlere sahip bir arabirim / soyut sınıftır.

Deseni uygulamak için, önce ilgili koleksiyon (istemci) üzerinde tekrar edebilen bir beton üretmek için bir yineleyici uygulamamız gerekir. Daha sonra toplama (istemci) yukarıdaki yineleyicinin bir örneğini döndürmek için toplayıcıyı uygular.

İşte UML diyagramı Yineleyici Desen

Yani temelde c #, IEnumerable soyut toplama ve IEnumerator soyut Iterator olduğunu. IEnumerable, istenen türde bir IEnumerator örneği oluşturmaktan sorumlu tek bir GetEnumerator yöntemine sahiptir. Listeler gibi koleksiyonlar IEnumerable uygulamasını uygular.

Misal. Biz bir yöntem olduğunu varsayalım Sağlar getPermutations(inputString)bir dize ve döner tüm permütasyon yöntemi bir örneğini döndürürIEnumerable<string>

Permütasyon sayısını saymak için aşağıdaki gibi bir şey yapabiliriz.

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

C # derleyicisi aşağı yukarı yukarıdakileri

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

Herhangi bir sorunuz varsa lütfen sormaktan çekinmeyin.


2

Küçük bir katkı.

Birçoğunun 'ne zaman kullanılacağını' ve 'foreach ile kullan'ı açıkladığı gibi. Burada hem IEnumerable hem de IEnumerator arasındaki fark hakkında soruda istendiği gibi Başka Durumlar Farkı eklemeyi düşündüm .

Aşağıdaki tartışma örnekleri dayalı aşağıdaki kod örneği oluşturdu.

IEnumerable, IEnumerator vs foreach, ne zaman kullanılır IEnumerator ve IEnumerable arasındaki fark nedir?

Numaralandırıcı diğer numaralar yinelendiğinde işlev çağrıları arasındaki durumu (yineleme konumu) korur.

İşte anlamak için yorumlarla test örneği.

Uzmanlar lütfen beni ekleyin / düzeltin.

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

Bu farkları fark ettim:

C. Listeyi farklı bir şekilde yineliyoruz, foreach IEnumerable için ve while döngüsü IEnumerator için kullanılabilir.

B. Bir yöntemden diğerine geçtiğimizde IEnumerator geçerli dizini hatırlayabilir (geçerli dizinle çalışmaya başlar), ancak IEnumerable dizini hatırlayamaz ve dizini başlangıca sıfırlar. Bu videoda daha fazlası https://www.youtube.com/watch?v=jd3yUjGc9M0


1

IEnumerableve IEnumeratorher ikisi de C # 'daki arayüzlerdir.

IEnumerablebir arabirim GetEnumerator()döndüren tek bir yöntemi tanımlayan bir IEnumeratorarabirimdir.

Bu, bir deyimle IEnumerablekullanılabilen bir koleksiyona salt okunur erişim için çalışır foreach.

IEnumeratoriki yöntemi vardır MoveNextve Reset. Ayrıca adlı bir özelliği vardır Current.

Aşağıda IEnumerable ve IEnumerator'ın uygulanması gösterilmektedir.


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
  */
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.