क्या कोई मुझे IEnumerable और IEnumerator समझा सकता है? [बन्द है]


272

क्या कोई मुझे IEnumerable और IEnumerator समझा सकता है?

उदाहरण के लिए, जब इसे फोरचेक पर उपयोग करना है? IEnumerable और IEnumerator के बीच क्या अंतर है? हमें इसका उपयोग करने की आवश्यकता क्यों है?


54
जावा और जावास्क्रिप्ट के बाद से यह सबसे खराब नामकरण मिश्रण है
मैथ्यू लॉक

@MatthewLock क्या आप इसका मतलब समझा सकते हैं?
डेविड क्लेम्फनर

जवाबों:


274

उदाहरण के लिए, जब इसे फोरचेक पर उपयोग करना है?

आप IEnumerable"ओवर" का उपयोग नहीं करते हैं foreach। लागू IEnumerableकरना foreach संभव का उपयोग करता है

जब आप कोड लिखते हैं जैसे:

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

यह कार्यात्मक रूप से लिखने के बराबर है:

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

"कार्यात्मक रूप से समतुल्य," से मेरा मतलब है कि वास्तव में क्या संकलक कोड में बदल जाता है। जब तक लागू नहीं होता foreachहै bazआप इस उदाहरण में उपयोग नहीं कर सकते । bazIEnumerable

IEnumerableइसका मतलब है कि bazविधि को लागू करता है

IEnumerator GetEnumerator()

IEnumeratorयह विधि जिस ऑब्जेक्ट पर लौटती है, उसे विधियों को लागू करना चाहिए

bool MoveNext()

तथा

Object Current()

पहली विधि उस ऑब्जेक्ट में अगली ऑब्जेक्ट को आगे IEnumerableबढ़ाती है जिसने एन्यूमरेटर बनाया, falseयदि यह किया गया है, तो वापस आ रहा है और दूसरा वर्तमान ऑब्जेक्ट को लौटाता है।

.Net में कुछ भी जो आप लागू कर सकते हैं IEnumerable। यदि आप अपनी खुद की कक्षा का निर्माण कर रहे हैं, और यह पहले से ही लागू होने वाले वर्ग से विरासत में नहीं मिला है IEnumerable, तो आप अपने वर्ग foreachको लागू करके बयानों में प्रयोग करने योग्य बना सकते हैं IEnumerable(और एक एन्यूमरेटर वर्ग बनाकर कि इसकी नई GetEnumeratorपद्धति वापस आ जाएगी)।


15
मुझे लगता है कि जब मूल पोस्टर ने "ओवरआर्क" कहा था, तो उनका मतलब था "जब मुझे गेटिउनरेटर () / मूवनेट () को स्पष्ट रूप से एक फॉरेस्ट लूप का उपयोग करने के बजाय कॉल करना चाहिए।" हांलांकि इसकी कीमत के बारे निश्चित नहीं हूँ।
mqp

6
आह, मुझे लगता है कि तुम सही हो। खैर, मेरी पोस्ट में जवाब का निहितार्थ: यह कोई फर्क नहीं पड़ता, क्योंकि कंपाइलर वैसे भी क्या करता है। तो क्या आसान है, यानी foreach का उपयोग करें।
रॉबर्ट रॉसनी

12
यह उत्तर पूरी कहानी नहीं बताता है। अनगिनत वस्तुओं को IEnumerable को लागू करने की आवश्यकता नहीं है; उन्हें केवल एक गेटनेमर विधि की आवश्यकता होती है जो एक प्रकार का उदाहरण देता है जिसमें बदले में एक bool MoveNext()विधि और Currentकिसी भी प्रकार की संपत्ति होती है। यह "डक टाइपिंग" दृष्टिकोण सी # 1.0 में मूल्य-प्रकार के संग्रह की गणना करते समय मुक्केबाजी से बचने के तरीके के रूप में लागू किया गया था।
15

3
ऊपर से बाहर निकलने और वर्कथ्रू के माध्यम से काम करने के साथ: (टी) के IEnumerable को लागू करना आपके पास बहुत बढ़िया स्रोत हैं।
Ruedi

4
क्या यह C ++ की तरह है iterator?
मैट जी

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

हालांकि ऐसा लग सकता है कि केवल सरणी प्रकार इस निर्माण का उपयोग कर सकते हैं, मामले की सच्चाई किसी भी प्रकार का है जो गेटनेमर (नामक एक विधि का समर्थन करता है) का मूल्यांकन फ़ोरच निर्माण द्वारा किया जा सकता है। उदाहरण के लिए, मेरा अनुसरण करें!

मान लीजिए कि हमारे पास गैराज क्लास है:

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

आदर्श रूप से, यह फॉरेक्स कंस्ट्रक्शन का उपयोग करके गैराज ऑब्जेक्ट के सबिटम्स पर पुनरावृति करने के लिए सुविधाजनक होगा, डेटा मानों की एक सरणी की तरह:

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

अफसोस की बात है कि कंपाइलर आपको सूचित करता है कि गैराज क्लास गेटनेमर () नाम की एक विधि को लागू नहीं करता है। इस विधि को IEnumerable इंटरफ़ेस द्वारा औपचारिक रूप दिया गया है, जो System.Collections नाम स्थान के भीतर गुप्त पाया जाता है। इस व्यवहार का समर्थन करने वाले वर्ग या संरचनाएं विज्ञापन देती हैं कि वे कॉलगर्ल में निहित उपप्रकारों को उजागर करने में सक्षम हैं (इस उदाहरण में, स्वयं फ़ॉरवर्ड कीवर्ड)। इस मानक .NET इंटरफ़ेस की परिभाषा इस प्रकार है:

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

जैसा कि आप देख सकते हैं, GetEnumerator () विधि System.Collections.IEVumter नाम के किसी अन्य इंटरफ़ेस के संदर्भ को संदर्भित करता है। यह इंटरफ़ेस 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 (), करंट, और रीसेट () के अनुकूलित संस्करण प्रदान करने के लिए स्वतंत्र हैं, एक सरल तरीका है। जैसा कि 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();
   }
}

आपके गैराज प्रकार को अपडेट करने के बाद, आप सुरक्षित रूप से 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();
}

ऐसा करने से, आकस्मिक ऑब्जेक्ट उपयोगकर्ता को गैराज का गेटएनीमेटर () विधि नहीं मिलेगी, जबकि फ़ॉरच निर्माण में आवश्यक होने पर पृष्ठभूमि में इंटरफ़ेस प्राप्त होगा।

प्रो सी # 5.0 और .NET 4.5 फ्रेमवर्क से अनुकूलित


1
शानदार जवाब, धन्यवाद! हालांकि मेरे पास भी एक प्रश्न है। पहले उदाहरण में आप आड़ू का उपयोग करके सरणी पर लूप करते हैं, लेकिन फिर आप इसे दूसरे उदाहरण में नहीं कर सकते। क्या यह इसलिए है क्योंकि सरणी एक वर्ग में है या क्योंकि इसमें ऑब्जेक्ट हैं?
कालेब पामक्विस्ट

महान व्याख्या के लिए धन्यवाद। मेरा एकमात्र सवाल यह है कि सिर्फ एक तरीका ही क्यों नहीं Garageहै carArray? इस तरह से आपको GetEnumeratorअपने आप को लागू करने की आवश्यकता नहीं है , क्योंकि Arrayयह पहले से ही ऐसा करता है। जैसेforeach(Car c in carLot.getCars()) { ... }
निक रोलैंडो

62

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
अच्छा, यह बताता है (अन्य पदों के साथ) अपनी कक्षा को एक में परिवर्तित करने के लिए कि आप अपनी सामग्री पर पुनरावृति करने के लिए "फ़ॉरच" का उपयोग कैसे कर सकते हैं।
कंटैंगो

54

सादृश्य + कोड वॉकथ्रू के माध्यम से स्पष्टीकरण

पहले कोड के बिना एक स्पष्टीकरण, फिर मैं इसे बाद में जोड़ूंगा।

मान लीजिए कि आप एक एयरलाइन कंपनी चला रहे हैं। और प्रत्येक विमान में आप विमान में उड़ान भरने वाले यात्रियों के बारे में जानकारी जानना चाहते हैं। मूल रूप से आप विमान को "पार" करने में सक्षम होना चाहते हैं। दूसरे शब्दों में, आप सामने की सीट पर शुरू करने में सक्षम होना चाहते हैं, और फिर विमान के पीछे की ओर अपना काम करना चाहते हैं, यात्रियों से कुछ जानकारी पूछते हैं: वे कौन हैं, वे कहाँ से हैं आदि। एक हवाई जहाज केवल यह कर सकता है। , अगर यह होता है:

  1. गणनीय, और
  2. अगर यह एक काउंटर है।

ये आवश्यकताएं क्यों? क्योंकि यही इंटरफ़ेस की आवश्यकता है।

यदि यह सूचना अधिभार है, तो आपको केवल यह जानना होगा कि आप विमान में प्रत्येक यात्री से कुछ प्रश्न पूछना चाहते हैं, जो कि पहले से शुरू हो रहा है और आखिरी तक आपका रास्ता बना रहा है।

गणनीय का क्या अर्थ है?

यदि कोई एयरलाइन "काउंटेबल" है, तो इसका मतलब है कि विमान में एक फ्लाइट अटेंडेंट मौजूद होना चाहिए, जिसका एकमात्र काम गिनती करना है - और यह फ्लाइट अटेंडेंट MUST को बहुत ही विशिष्ट तरीके से गिनता है:

  1. काउंटर / फ्लाइट अटेंडेंट MUST पहले यात्री (सभी के सामने जहां वे सुरक्षा प्रदर्शित करते हैं, लाइफ जैकेट को कैसे रखा जाए आदि) से पहले शुरू होते हैं।
  2. वह / वह (यानी फ्लाइट अटेंडेंट) MUST "नेक्स्ट" को ऐसली अप टू फर्स्ट सीट।
  3. वह / वह तो रिकॉर्ड करने के लिए है: (i) जो व्यक्ति सीट पर है, और (ii) गलियारे में उनका वर्तमान स्थान।

गिनने की प्रक्रिया

एयरलाइन के कप्तान हर यात्री पर एक रिपोर्ट चाहते हैं, जब उनकी जांच की जाती है या उनकी गणना की जाती है। इसलिए पहली सीट पर व्यक्ति से बात करने के बाद, फ़्लाइट-अटेंडेंट / काउंटर फिर कप्तान को रिपोर्ट करता है, और जब रिपोर्ट दी जाती है, तो काउंटर को गलियारे में उसकी सही स्थिति याद रहती है और वह सही जगह पर गिनती जारी रखता है, जहाँ उसने छोड़ा था बंद।

इस तरीके से कप्तान को वर्तमान व्यक्ति की जांच के बारे में जानकारी देने में हमेशा सक्षम होता है। इस तरह, अगर उसे पता चलता है कि यह व्यक्ति मैनचेस्टर सिटी को पसंद करता है, तो वह उस यात्री को तरजीह दे सकता है आदि।

  • काउंटर तब तक चलता रहता है जब तक वह विमान के अंतिम छोर तक नहीं पहुंच जाता।

आइए इसे IEnumerables के साथ टाई करें

  • एक विमान पर यात्रियों का बस एक संग्रह है। नागरिक उड्डयन कानून - ये मूल रूप से नियम हैं जो सभी IEnumerables का पालन करना चाहिए। हर बार एयरलाइन परिचारक कैसपस जानकारी के साथ कप्तान के पास जाता है, हम मूल रूप से यात्री को कप्तान को 'उपज' देते हैं। कप्तान मूल रूप से यात्री के साथ जो चाहे कर सकता है - विमान में यात्रियों को पुन: व्यवस्थित करने के अलावा। इस मामले में, उन्हें अधिमान्य उपचार दिया जाता है यदि वे मैनचेस्टर सिटी का अनुसरण करते हैं (उघ!)

    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 सिर्फ "गणनीय" के लिए एक फैंसी शब्द है। दूसरे शब्दों में, एक enumerable आपको 'गणना' (यानी गणना) करने की अनुमति देता है।


23

IEnumerable लागू करता है GetEnumerator। जब बुलाया जाता है, तो वह विधि एक IEnumerator लौटाएगा जो MoveNext, रीसेट और करंट को कार्यान्वित करता है।

इस प्रकार जब आपकी कक्षा IEnumerable लागू करती है, तो आप कह रहे हैं कि आप एक विधि (GetEnumerator) को कॉल कर सकते हैं और एक नया ऑब्जेक्ट वापस प्राप्त कर सकते हैं (एक IEnumerator) जिसे आप फॉर्च जैसे लूप में उपयोग कर सकते हैं।


18

IEnumerable को लागू करना आपको सूची के लिए IEnumerator प्राप्त करने में सक्षम बनाता है।

IEnumerator उपज कीवर्ड का उपयोग करके सूची में आइटम के लिए अनुक्रम शैली तक पहुँचने की अनुमति देता है।

फोरसीट कार्यान्वयन (जावा 1.4 में, उदाहरण के लिए) से पहले, सूची को पुनरावृत्त करने का तरीका सूची से एक एन्यूमरेटर प्राप्त करना था, फिर इसे सूची में "अगले" आइटम के लिए पूछें, जब तक कि मूल्य अगले के रूप में वापस आ गया हो आइटम शून्य नहीं है। फॉरच बस उस भाषा की विशेषता के रूप में स्पष्ट रूप से करता है, उसी तरह जो लॉक () पर्दे के पीछे मॉनिटर वर्ग को लागू करता है।

मुझे उम्मीद है कि सूचियों पर फॉर्च्यूनर काम करेगा क्योंकि वे IEnumerable को लागू करते हैं।


अगर इसकी एक सूची के लिए मैं सिर्फ फ़ार्च का उपयोग क्यों नहीं कर सकता?
prodev42

.Net बत्तख के कथन को टाइप करता है, लेकिन IEnumerable / IEnumerable <T> यह कहने का उपयुक्त तरीका है कि आपकी कक्षा को एनुमरेट किया जा सकता है।
user7116

15
  • IEnumerable को लागू करने वाली एक वस्तु दूसरों को इसके प्रत्येक आइटम (एक एन्यूमरेटर द्वारा) का दौरा करने की अनुमति देती है ।
  • IEnumerator लागू करने वाली वस्तु पुनरावृत्ति कर रही है। यह एक enumerable वस्तु पर पाशन है।

सूची, ढेर, पेड़ों के रूप में अनगिनत वस्तुओं के बारे में सोचो।


12

IEnumerable और IEnumerator (और उनके सामान्य समकक्षों IEnumerable <टी> और IEnumerator <टी>) के आधार इंटरफेस हैं इटरेटर में कार्यान्वयन नेट फ्रेमवर्क कक्षा libray संग्रह

IEnumerable सबसे आम इंटरफ़ेस है जिसे आप वहां के अधिकांश कोड में देखेंगे। यह फ़ॉरच लूप, जनरेटर (थिंक यील्ड ) को सक्षम बनाता है और अपने छोटे इंटरफ़ेस की वजह से इसका उपयोग तंग सार बनाने के लिए किया जाता है। IEnumerable IEnumerator पर निर्भर करता है

दूसरी ओर, IEnumerator , थोड़ा निचले स्तर का पुनरावृत्ति इंटरफ़ेस प्रदान करता है। इसे स्पष्ट पुनरावृत्त के रूप में जाना जाता है पुनरावृत्त के जो प्रोग्रामर को पुनरावृत्ति चक्र पर अधिक नियंत्रण देता है।

IEnumerable

IEnumerable एक मानक इंटरफ़ेस है जो संग्रह का समर्थन करने में सक्षम बनाता है जो इसे समर्थन करता है (वास्तव में, सभी संग्रह प्रकार जो मैं आज के IEnumerable लागू करता हूं ) के बारे में सोच सकता हूं । कंपाइलर समर्थन भाषा सुविधाओं की तरह अनुमति देता है foreach। सामान्य शब्दों में, यह इस निहित पुनरावृत्ति कार्यान्वयन को सक्षम करता है

फोरपॉप लूप

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

मुझे लगता है कि IEnumerable इंटरफेस foreachका उपयोग करने के लिए लूप मुख्य कारणों में से एक है । क्लासिक सी की तुलना में बहुत रसीला वाक्यविन्यास और समझने में बहुत आसान हैforeachछोरों के शैली जहां आपको यह देखने के लिए विभिन्न चर की जांच करने की आवश्यकता है कि यह क्या कर रहा था।

उपज खोजशब्द

संभवतः एक कम ज्ञात विशेषता यह है कि IEnumerable C #yield return और yield breakकथन के उपयोग के साथ जनरेटर को भी सक्षम बनाता है ।

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

कपोल-कल्पना

व्यवहार में एक और सामान्य परिदृश्य न्यूनतम सार प्रदान करने के लिए IEnumerable का उपयोग कर रहा है । क्योंकि यह एक छोटा-सा और केवल-पढ़ने वाला इंटरफ़ेस है, आपको अपने संग्रह को IEnumerable ( उदाहरण के लिए सूची के बजाय ) के रूप में उजागर करने के लिए प्रोत्साहित किया जाता है । इस तरह से आप अपने ग्राहक के कोड ( उदाहरण के लिए एक लिंक्डलिस्ट में सूची में बदलाव ) को तोड़ने के बिना अपने कार्यान्वयन को बदलने के लिए स्वतंत्र हैं ।

पकड़ लिया

एक व्यवहार के बारे में पता है कि स्ट्रीमिंग कार्यान्वयन में (उदाहरण के लिए एक डेटाबेस से पंक्ति द्वारा डेटा पंक्ति को पुनः प्राप्त करना, पहले मेमोरी में सभी परिणामों को लोड करने के बजाय) आप एक से अधिक बार संग्रह पर पुनरावृति नहीं कर सकते । यह सूची जैसे इन-मेमोरी संग्रह के विपरीत है , जहां आप समस्याओं के बिना कई बार पुनरावृति कर सकते हैं। उदाहरण के लिए, 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पुनरावृत्तियों को करने के लिए उपयोग की जाने वाली वास्तविक वस्तु है। यह सूची में एक वस्तु से दूसरे तक जाने को नियंत्रित करता है।

ज्यादातर समय, IEnumerableऔर IEnumeratorपारदर्शी रूप से एक foreachलूप के हिस्से के रूप में उपयोग किया जाता है ।


6

IEnumerable और IEnumerator के बीच अंतर:

  • IEnumerable आंतरिक रूप से IEnumerator का उपयोग करता है।
  • IEnumerable को पता नहीं है कि कौन सी वस्तु / वस्तु निष्पादित हो रही है।
  • जब भी हम IEnumerator को किसी अन्य फ़ंक्शन में पास करते हैं, तो यह आइटम / ऑब्जेक्ट की वर्तमान स्थिति को जानता है।
  • जब भी हम एक IEnumerable संग्रह को किसी अन्य फ़ंक्शन में पास करते हैं, तो यह आइटम / ऑब्जेक्ट की वर्तमान स्थिति को नहीं जानता है (यह पता नहीं है कि कौन सा आइटम निष्पादन करता है)

    IEnumerable का एक तरीका GetEnumerator () है

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

IEnumerator के पास एक संपत्ति है जिसे करंट और दो विधियाँ कहा जाता है, रीसेट () और MoveNext () (जो किसी सूची में किसी आइटम की वर्तमान स्थिति को जानने के लिए उपयोगी है)।

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

अब हम उस वर्ग को परिभाषित करेंगे जो हमारे वर्ग ग्राहक के लिए एक संग्रह के रूप में कार्य करेगा। ध्यान दें कि यह इंटरफ़ेस 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.
        }
    }

अब हम नीचे की तरह हमारे संग्रह पर फॉर्च लूप का उपयोग कर सकते हैं;

    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

Iterator पैटर्न की समझ आपके लिए मददगार होगी। मैं वही पढ़ने की सलाह देता हूं।

इटरेटर पैटर्न

उच्च स्तर पर किसी भी प्रकार के संग्रह के माध्यम से पुनरावृत्ति का एक मानक तरीका प्रदान करने के लिए इट्रेटर पैटर्न का उपयोग किया जा सकता है। इटरेटर पैटर्न में हमारे 3 प्रतिभागी हैं, वास्तविक संग्रह (क्लाइंट), एग्रीगेटर और इटरेटर। कुल एक इंटरफ़ेस / अमूर्त वर्ग है जिसमें एक विधि है जो एक पुनरावृत्ति देता है। Iterator एक इंटरफ़ेस / अमूर्त वर्ग है जिसमें ऐसी विधियाँ हैं जो हमें एक संग्रह के माध्यम से पुनरावृति करने की अनुमति देती हैं।

पैटर्न को लागू करने के लिए हमें सबसे पहले एक संकलक को लागू करने के लिए एक ठोस बनाने की आवश्यकता होती है जो संबंधित संग्रह (ग्राहक) पर पुनरावृति कर सकता है फिर संग्रह (ग्राहक) उपर्युक्त पुनरावृत्त की एक आवृत्ति को वापस करने के लिए एग्रीगेटर को लागू करता है।

यहाँ UML आरेख है इटरेटर पैटर्न

तो मूल रूप से c # में, IEnumerable सार समुच्चय है और IEnumerator सार Iterator है। IEnumerable में एक एकल विधि GetEnumerator है जो वांछित प्रकार के IEnumerator की आवृत्ति बनाने के लिए जिम्मेदार है। सूचियों की तरह संग्रह IEnumerable को लागू करते हैं।

उदाहरण। मान लीजिए कि हमारे पास एक विधि है getPermutations(inputString)जो एक स्ट्रिंग के सभी क्रमपरिवर्तन लौटाती है और यह विधि एक उदाहरण देती हैIEnumerable<string>

क्रमपरिवर्तन की संख्या की गणना करने के लिए हम नीचे जैसा कुछ कर सकते हैं।

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

सी # संकलक कमोबेश उपरोक्त को परिवर्तित करता है

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

यदि आपके कोई प्रश्न हैं, तो कृपया पूछने में संकोच न करें।


2

एक मामूली योगदान।

जैसा कि उनमें से कई 'कब और कैसे इस्तेमाल करना है' के बारे में बताते हैं। मैंने दोनों IEnumerable IEnumerator के बीच अंतर के बारे में अनुरोध के रूप में यहां एक और राज्य अंतर जोड़ने के बारे में सोचा ।

मैंने नीचे चर्चा के धागे के आधार पर नीचे दिए गए कोड का नमूना बनाया।

IEnumerable, IEnumerator vs foreach, जब उपयोग करने के लिए IEnumerator और IEnumerator में क्या अंतर है?

एन्यूमरेटर फ़ंक्शन कॉल के बीच राज्य (पुनरावृत्ति स्थिति) को संरक्षित करता है, जबकि दूसरी ओर एनुमरेबल इसे पुनरावृत्त नहीं करता है।

यहाँ समझने के लिए टिप्पणियों के साथ परीक्षण किया गया उदाहरण है।

विशेषज्ञ कृपया मुझे जोड़ें / सुधारें।

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. हम सूची को अलग-अलग तरीके से बनाते हैं, IEnumerable के लिए foreach का उपयोग किया जा सकता है और जबकि IEnumerator के लिए लूप का।

B. IEnumerator वर्तमान सूचकांक को याद कर सकता है जब हम एक विधि से दूसरे में जाते हैं (यह वर्तमान सूचकांक के साथ काम करना शुरू करते हैं) लेकिन IEnumerable सूचकांक को याद नहीं रख सकता है और यह सूचकांक को शुरुआत में रीसेट कर देता है। इस वीडियो में और अधिक https://www.youtube.com/watch?v=jd3yUjGc9M0


1

IEnumerableऔर IEnumeratorदोनों सी # में इंटरफेस हैं।

IEnumerableएक इंटरफ़ेस को परिभाषित करने वाली एकल विधि को परिभाषित करने GetEnumerator()वाला IEnumeratorइंटरफ़ेस है।

यह एक संग्रह के रीड-ओनली एक्सेस के लिए काम करता है जो IEnumerableएक foreachस्टेटमेंट के साथ प्रयोग किया जा सकता है ।

IEnumeratorदो तरीके हैं, 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
  */
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.