2010-01-02 7 views
7

मैं सोच रहा था कि GetEnumerator() विधि को IENumerator से क्यों निकाल दिया गया था और IENumerable में रखा गया था। ऐसा लगता है कि यह IENumerator में सभी गणक विधियों को रखने के लिए और अधिक समझदारी होगी।GetEnumerator() IENumerator से एक अलग इंटरफ़ेस में संग्रहीत क्यों किया गया था?

धन्यवाद,

स्कॉट

उत्तर

17

खुद से पूछें "कल्पना करें कि यह सच था"।

यदि सभी गणना विधियां एक ही इंटरफेस पर थीं, तो दो कॉलर्स एक ही सूची में एक ही सूची को कैसे समझा सकते हैं?

दो इंटरफेस हैं क्योंकि कोई कहता है, "आप मुझे गिन सकते हैं," जबकि दूसरा कहता है, "यहां एक ऐसी वस्तु है जो किसी दिए गए गणित कार्य का ट्रैक रखती है।"

IEnumerable इंटरफ़ेस एक ऐसा कारखाना है जो आपको जितनी चाहें IEnumerator ऑब्जेक्ट्स बनाता है। कैसे और जब उन गणकों का उपयोग किया जाता है उपभोक्ता तक।

+1

+1 को collaped है। यह एक अच्छा उदाहरण है कि इंटरफेस अलग और अलग क्यों हैं। एक और कारण यह है कि एक ही प्रकार के संग्रह को विभिन्न तरीकों से समझा जा सकता है। एक बाइनरी पेड़ की कल्पना करें - आप उपसर्ग, इंफिक्स, पोस्टफिक्स, और चौड़ाई-पहले ट्रैवर्सल (केवल कुछ नाम देने के लिए) कर सकते हैं। इंटरफेस को अलग रखने से एक ही, सरल इंटरफेस के माध्यम से एक ही संरचना पर विभिन्न प्रकार के ट्रैवर्सल किए जाने की अनुमति मिलती है। – LBushkin

+0

आपके उत्तर के लिए धन्यवाद! यह अब मेरे लिए स्पष्ट है। –

7

IEnumerable का तात्पर्य है कि वस्तु एक संग्रह या डेटा जो एक रैखिक फैशन में अधिक दोहराया जा सकता है का स्रोत है। IEnumerator वास्तविक कार्यान्वयन के लिए इंटरफेस है जो पुनरावृत्ति करता है।

4

क्योंकि "आईन्यूमेरेबल" कहता है "आओ, मुझे बताएं" (और फिर आप कहते हैं- कैसे, मुझे गणक दें), हालांकि "आईन्यूमेरेटर" कहता है "मैं आपके संग्रह की गणना कर सकता हूं!" और आपके पास पहले से ही है, आपको और भी प्राप्त करने की आवश्यकता नहीं है।

0

क्योंकि अक्सर गणना करने वाली चीज केवल गणना की जाने वाली चीज़ से संबंधित है (अगर बिल्कुल)। यदि IENumerable और IENumerator एक ही इंटरफ़ेस थे, तो उन्हें साझा नहीं किया जा सका, या आपको GetEnumerator पर कुछ अवांछित तर्क होना होगा जिसने आपको ऑब्जेक्ट में गणना करने की अनुमति दी है। उन्हें विभाजित करने से गणना के आधारभूत संरचना को विभिन्न प्रकारों में संभावित रूप से साझा किया जा सकता है।

2

आपको यहां बहुत अच्छे जवाब मिल गए हैं। बस कुछ जोर। एक गणक राज्य रखता है, यह संग्रहित होने वाले संग्रह में वर्तमान वस्तु का ट्रैक रखता है। IENumerator.Current के माध्यम से उपलब्ध है। और यह जानता है कि उस स्थिति को कैसे बदला जाए, IENumerator.MoveNext()। राज्य को रखने के लिए एक अलग वस्तु की आवश्यकता होती है जो राज्य को स्टोर करती है। उस स्थिति को संग्रह ऑब्जेक्ट के अंदर आसानी से संग्रहीत नहीं किया जा सकता है क्योंकि केवल एक संग्रह वस्तु है लेकिन एक से अधिक गणक हो सकते हैं।

मैंने वाक्यांश को "आसानी से" इस्तेमाल किया क्योंकि वास्तव में संग्रह के लिए अपने गणक का ट्रैक रखना संभव है। आखिरकार, यह संग्रह वर्ग 'GetEnumerator() विधि के लिए एक कॉल था जो इटेटरेटर लौटा। .NET ढांचे में एक संग्रह वर्ग है जो यह करता है, माइक्रोसॉफ्ट। VisualBasic.Collection। इसे अपने संग्रह वर्ग के लिए एक वीबी 6 अनुबंध लागू करने की आवश्यकता थी और यह अनुबंध निर्दिष्ट करता है कि गणना के दौरान संग्रह को बदलना कानूनी है। जिसका अर्थ यह है कि जब संग्रह संशोधित होता है, तो इसे बनाए गए सभी इटरेटर ऑब्जेक्ट्स के साथ कुछ उचित करने की आवश्यकता होती है।

वे एक बहुत अच्छी चाल के साथ आए, वीक रेफरेंस इस से प्रेरित हो सकता है। परावर्तक द्वारा दिखाए गए कोड पर एक नज़र डालें। प्रेरणादायक चीजें संग्रह कक्षाओं में कुछ और खोएं और "संस्करण" ढूंढें। बहुत बढ़िया चाल

+0

मुझे आश्चर्य है कि क्लीनर संग्रह क्यों उपलब्ध नहीं है (कम से कम नेट 4.0 से पहले) जो ऐसा कर सकता है? संग्रह के माध्यम से गणना करना और चुनिंदा तत्वों को हटाने से आम ऑपरेशन की तरह लग रहा है। – supercat

+0

@super: क्योंकि यह मूल रूप से तोड़ रहा है। आप संग्रह के एक उत्परिवर्तन के लिए इटरेटर को क्षतिपूर्ति करने में सक्षम हो सकते हैं। लेकिन किसी तत्व को हटाने और इसे किसी अन्य स्थिति में वापस डालने की तरह कुछ तोड़ने जा रहा है। इटरेटर एक तत्व को दो बार देखेगा या बिल्कुल नहीं। इसके अलावा, इटरेटर्स के सभी लाइव उदाहरणों का ट्रैक रखना काफी महंगा है। –

+0

मैं समझ सकता हूं कि 'सामान्य' संग्रह ऐसी सुविधाओं का समर्थन नहीं करेंगे, लेकिन संग्रह में उपयोगी अर्थशास्त्र का प्रबंधन होता है जो कि यदि वे बिना किसी क्विर्कनेस के कक्षा में कार्यान्वित किए जाते हैं तो इससे भी अधिक उपयोगी होगा। कोई भी इस तरह के अर्थशास्त्र नहीं चाहता, लेकिन कभी-कभी वे अच्छे होते हैं। असल में, मुझे iEnumerator के अधिक स्वाद देखा होगा! अनुप्रयोग आवश्यक अर्थशास्त्र के आधार पर एक का चयन कर सकते हैं (कुछ विधियों को जोड़ देंगे; अन्य केवल गारंटी जोड़ देंगे)। एक उपयोगी एक iPurgeEnumerator होगा: प्रत्येक आइटम के साथ एक predicate कॉल करें और यदि सही हो तो हटा दें। – supercat

0

minlinq पर बार्ट डी स्मेट की पोस्ट पढ़ने के बाद मुझे अब विश्वास नहीं है कि दो इंटरफेस को विभाजित करने की सख्ती से आवश्यकता है।

उदाहरण के लिए - ऊपर के लिंक में, IEnumerable/IEnumerator एक भी विधि इंटरफ़ेस

Func<Func<Option<T>>> 

और कुछ बुनियादी कार्यान्वयन

public static class FEnumerable 
{ 
    public static Func<Func<Option<T>>> Empty<T>() 
    { 
     return() =>() => new Option<T>.None(); 
    } 

    public static Func<Func<Option<T>>> Return<T>(T value) 
    { 
     return() => 
     { 
      int i = 0; 
      return() => 
       i++ == 0 
       ? (Option<T>)new Option<T>.Some(value) 
       : (Option<T>)new Option<T>.None(); 
     }; 
    } 

    ... 

} 

public static Func<Func<Option<T>>> Where<T>(this Func<Func<Option<T>>> source, Func<T, bool> filter) 
{ 
    return source.Bind(t => filter(t) ? FEnumerable.Return(t) : FEnumerable.Empty<T>()); 
} 
संबंधित मुद्दे

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