2009-07-06 18 views
22

का उपयोग करने के लिए जब मैं आईनेमेरेबल और आईन्यूमेरेटर के माध्यम से जा रहा था, लेकिन एक बिंदु स्पष्ट रूप से नहीं मिला .. अगर हमारे पास foreach है, तो हमें इन दो इंटरफेस की आवश्यकता क्यों है? क्या कोई परिदृश्य है जहां हमें इंटरफेस का उपयोग करना होगा। अगर हां, तो क्या कोई उदाहरण के साथ समझा सकता है। कोई सुझाव और टिप्पणी का स्वागत है। धन्यवाद।IENumerable, IENumerator बनाम foreach,

उत्तर

46

foreachकई मामलों में इंटरफेस का उपयोग करता है। यदि आप को अनुक्रमित करना चाहते हैं तो foreach का उपयोग कर सकते हैं तो आपको इंटरफेस की आवश्यकता है। (इटरेटर ब्लॉक आमतौर पर इस कार्यान्वयन कार्य को बहुत सरल बनाते हैं।)

हालांकि, कभी-कभी यह सीधे इटरेटर का उपयोग करने के लिए उपयोगी हो सकता है। एक अच्छा उदाहरण है जब दो अलग-अलग अनुक्रमों को "युग्मित" करने का प्रयास किया जाता है। उदाहरण के लिए, मान लीजिए कि आपको दो अनुक्रम प्राप्त होते हैं - नामों में से एक, उम्र में से एक, और आप दोनों को एक साथ मुद्रित करना चाहते हैं। आप लिख सकते हैं: अब

public T Max<T>(IEnumerable<T> items) 
{ 
    Comparer<T> comparer = Comparer<T>.Default; 

    using (IEnumerator<T> iterator = items.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      throw new InvalidOperationException("No elements"); 
     } 
     T currentMax = iterator.Current; 

     // Now we've got an initial value, loop over the rest 
     while (iterator.MoveNext()) 
     { 
      T candidate = iterator.Current; 
      if (comparer.Compare(candidate, currentMax) > 0) 
      { 
       currentMax = candidate; 
      } 
     } 
     return currentMax; 
    } 
} 

, अगर आप:

static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages) 
{ 
    using (IEnumerator<int> ageIterator = ages.GetEnumerator()) 
    { 
     foreach (string name in names) 
     { 
      if (!ageIterator.MoveNext()) 
      { 
       throw new ArgumentException("Not enough ages"); 
      } 
      Console.WriteLine("{0} is {1} years old", name, ageIterator.Current); 
     } 
     if (ageIterator.MoveNext()) 
     { 
      throw new ArgumentException("Not enough names"); 
     } 

    } 
} 

इसी तरह यह इटरेटर अगर आप का इलाज करना चाहते हैं (जैसे) आराम करने के लिए अलग तरह से पहले आइटम का उपयोग करने के लिए उपयोगी हो सकता IEnumerator<T> और IEnumerable<T> के बीच अंतर में रुचि रखते हैं, तो आप इसे डेटाबेस शब्दों में सोचना चाहेंगे: IEnumerable<T> एक तालिका के रूप में, और IEnumerator<T> एक कर्सर के रूप में सोचें। आप एक नया कर्सर देने के लिए एक टेबल से पूछ सकते हैं, और आप एक ही समय में एक ही टेबल पर एकाधिक कर्सर रख सकते हैं।

वास्तव में इस अंतर को समझने में कुछ समय लग सकता है, लेकिन केवल यह याद रखना कि एक सूची (या सरणी, या जो कुछ भी) में "जहां आप सूची में हैं" की कोई अवधारणा नहीं है लेकिन उस सूची/सरणी/जो भी है उस राज्य का थोड़ा सा सहायक है।

+0

धन्यवाद आपकी सभी मदद के लिए जॉन। मुझे अब मिल गया और इसे स्पष्ट करने के लिए और अधिक अध्ययन करेंगे। इसके अलावा मुझे निम्न लिंक बहुत उपयोगी लगता है: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

+0

यह एक उदाहरण है जहां आप IENumerator का उपयोग करके फंस गए हैं कुशल रहने के लिए। http://stackoverflow.com/questions/1018407/what-is-the-most- सुरुचिपूर्ण-way-to-get-a-set-of-items-by-index-from-a-collection/1025137#1025137 –

+0

@ जोन स्कीट मुझे वास्तव में जिस तरह से आपने मैक्स विधि को कोड किया था उसे पसंद किया। मेरे पास एक सवाल है आपने आईनंबरेटर के साथ निर्माण का उपयोग किया था। मुझे पता है कि इसके अंदर क्या आता है()। आपने इसे आईनंबरेटर पर क्यों इस्तेमाल किया? –

8

जो जॉन ने कहा।

  • IEnumerable या IEnumerable<T>: इस एक वस्तु कहा गया है कि यह आप एक इटरेटर है कि आप अनुक्रम/संग्रह से अधिक पार करने के लिए उपयोग कर सकते हैं दे सकते हैं को लागू करने से/सेट
  • IEnumerator या IEnumerator<T>: यदि आप GetEnumerator विधि परिभाषित फोन पिछले इंटरफ़ेस में, आपको एक इनिटरेटर ऑब्जेक्ट को एक आईनेमेरेटर संदर्भ के रूप में मिलता है। यह आपको MoveNext() को कॉल करने और वर्तमान ऑब्जेक्ट प्राप्त करने में सक्षम बनाता है।
  • foreach: एक सी # निर्माण/मुखौटा एक अर्थ में है कि आपको यह जानने की आवश्यकता नहीं है कि यह हुड के नीचे कैसे काम करता है। यह आंतरिक रूप से इटेटरेटर प्राप्त करता है और आप प्रत्येक आइटम (फोरैच ब्लॉक की सामग्री) के साथ क्या करना चाहते हैं, इस पर ध्यान केंद्रित करने के लिए सही तरीके कहता है। अधिकांश समय, आपको केवल तब तक फोरच की आवश्यकता होगी जब तक कि आप अपना खुद का प्रकार या कस्टम पुनरावृत्ति लागू नहीं कर रहे हों, इस मामले में आपको पहले 2 इंटरफेस को जानना होगा।
+0

धन्यवाद गिशू इसे मेरे लिए और अधिक स्पष्ट बनाने के लिए। मुझे यह लिंक बहुत उपयोगी लगता है: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

6
मन में

भालू है कि आप नहीं IEnumerator को लागू करने के है और उपयोग करने के लिए foreach उसके varients - IIRC, यह सब की जरूरत है एक GetEnumerator() विधि है कि एक वस्तु एक लौटने MoveNext() विधि है कि रिटर्न है एक बूल, और एक वस्तु वापस लौटने वाली एक संपत्ति। आपको IENumerator और IENumerable का उपयोग करने की आवश्यकता नहीं है, हालांकि यह आमतौर पर ऐसा करने का एक अच्छा विचार है। अधिक जानकारी के लिए here देखें।

+0

यह एक अजीब पुराना जानवर है, वह एक - आप कर सकते हैं बस दो तरीकों को लागू करें। ऐसा करने में बड़ी समस्या यह है कि टाइप सिस्टम को यह नहीं पता कि चीज गिनती है, इसलिए मुझे लगता है कि आपको ऑब्जेक्ट्स के लिंक के साथ इसका उपयोग करने में परेशानी होगी। –

+3

हां, यह अजीब है। हम उस सुविधा का समर्थन करने का कारण यह है कि आप सी # 1.0 में पूर्णांक का संग्रह लिख सकते हैं और मुक्केबाजी के बिना उन्हें समझा सकते हैं। अब हमारे पास आईई है, अब "पैटर्न" दृष्टिकोण की कोई आवश्यकता नहीं है। –

+1

@Eric Lippert: उस सुविधा का एक और फायदा है: यह संरचना गणनाकर्ताओं के लिए ढेर आवंटन से बचना संभव बनाता है, हालांकि मैं सुझाव दूंगा कि जिन कक्षाओं में GetEnumerator विधियों को एक स्ट्रक्चर लौटाया जाना चाहिए, उन्हें IENumerable.GetEnumerator विधियां जो कक्षाएं लौटाती हैं। – supercat

संबंधित मुद्दे