2010-05-02 9 views
10

क्या सी # कलेक्शन लाइब्रेरी में कोई डेटा संरचनाएं हैं जहां संरचना का संशोधन इटरेटर्स को अमान्य नहीं करता है?क्या कोई सी # संग्रह है जहां संशोधन इटरेटर्स को अमान्य नहीं करता है?

निम्नलिखित पर विचार करें:

List<int> myList = new List<int>(); 
myList.Add(1); 
myList.Add(2); 
List<int>.Enumerator myIter = myList.GetEnumerator(); 
myIter.MoveNext(); // myIter.Current == 1 
myList.Add(3); 
myIter.MoveNext(); // throws InvalidOperationException 
+0

क्या आप समझा सकते हैं कि आपको संग्रह को संशोधित करने की आवश्यकता क्यों है, जिसे आप पढ़ रहे हैं? आप जो चाहते हैं उसे करने का एक और तरीका हो सकता है। –

उत्तर

-1

उपयोग एक एक foreach के बजाय पाश, और फिर आप इसे संशोधित कर सकते हैं के लिए। हालांकि मैं इसे सलाह नहीं दूंगा ....

+2

हालांकि, यह सवाल का जवाब नहीं देता है। वह इटेटरेटर्स के बारे में पूछ रहा है, जरूरी नहीं कि केवल अनुक्रमित संग्रह। –

+0

ElementAt() एक्सटेंशन विधि के अतिरिक्त, सभी संग्रहों को अब अनुक्रमित किया जा सकता है। मुझे लगता है कि यह प्रश्नों का बहुत अधिक जवाब देता है .... – BFree

0

नहीं, वे मौजूद नहीं हैं। संरचना बदलते समय ALL C# मानक संग्रह संख्यात्मक को अमान्य कर देता है।

var myIter = new List<int>(myList).GetEnumerator(); 
1

यह करने के लिए एक ही रास्ता इससे पहले कि आप पुनरावृति सूची की एक प्रतिलिपि बनाने के लिए है।

एक गणनाकर्ता तब तक मान्य रहता है जब संग्रह अपरिवर्तित रहता है। यदि संग्रह में परिवर्तन किए जाते हैं, जैसे तत्वों को जोड़ना, संशोधित करना या हटाना, गणनाकर्ता को अपरिवर्तनीय रूप से अमान्य कर दिया गया है और अगली कॉल MoveNext या रीसेट को अमान्यऑपरेशन अपवाद फेंकता है। यदि संग्रहण MoveNext और Current के बीच संशोधित है, तो वर्तमान तत्व यह देता है कि यह पर सेट है, भले ही गणनाकर्ता पहले ही अमान्य हो।

8

this MSDN article on IEnumerator के अनुसार अमान्यकरण व्यवहार आप पाया है IEnumerable के सभी कार्यान्वयन के लिए आवश्यक है:

+6

वैसे तो, उन्होंने अपने दिशानिर्देशों का उल्लंघन किया है। 'System.Collections.Concurrent' में सभी संग्रह 'MoveNext' पर कॉल के बीच संग्रह के संशोधन की अनुमति देते हैं। –

+0

ऐसा इसलिए है क्योंकि इटेटरेटर संग्रह का एक स्नैपशॉट चलाता है, ताकि स्नैपशॉट को पुनरावृत्ति के दौरान संशोधित नहीं किया जा सके। – naasking

+1

दस्तावेज कहता है, और मैं समझता हूं कि तत्वों को जोड़ने और हटाने के लिए यह एक अच्छा विचार क्यों है, लेकिन यह स्पष्ट नहीं है कि किसी तत्व को संशोधित करने से गणक को अमान्य करना चाहिए। मैं समझ सकता हूं कि आप इसे इस तरह क्यों लागू कर सकते हैं, लेकिन आपको क्यों नहीं चाहिए। – yoyo

11

हां, .NET 4.0 में System.Collections.Concurrent नामस्थान पर एक नज़र डालें।

ध्यान दें कि इस नामस्थान में कुछ संग्रहों के लिए (उदा।, ConcurrentQueue<T>), यह केवल प्रश्न में संग्रह के "स्नैपशॉट" पर एक गणक को उजागर करके काम करता है।

the MSDN documentation on ConcurrentQueue<T> से:

गणन कतार के सामग्री की एक पल-इन-टाइम स्नैपशॉट प्रतिनिधित्व करता है। यह संग्रह प्राप्त करने के बाद संग्रह के किसी भी अद्यतन को प्रतिबिंबित नहीं करता है। गणक को कतार से पढ़ने और लिखने के साथ समवर्ती का उपयोग करने के लिए सुरक्षित है।

हालांकि, यह सभी संग्रहों के मामले में नहीं है। उदाहरण के लिए, ConcurrentDictionary<TKey, TValue>, आपको एक गणक देता है जो MoveNext पर कॉल के बीच अंतर्निहित संग्रह के अपडेट को बनाए रखता है।

the MSDN documentation on ConcurrentDictionary<TKey, TValue> से:

प्रगणक शब्दकोश से लौटे पढ़ता है और शब्दकोश में लिखते हैं के साथ समवर्ती उपयोग करने के लिए सुरक्षित है, लेकिन यह नहीं है का एक पल-इन-टाइम स्नैपशॉट का प्रतिनिधित्व शब्दकोष। अंकन के माध्यम से का खुलासा सामग्री में किए गए संशोधनों में GetEnumerator कहलाए जाने के बाद हो सकता है।

आप 4.0 की जरूरत नहीं है, तो मुझे लगता है कि दूसरों को सही कर रहे हैं और ऐसी कोई नेट द्वारा प्रदान संग्रह है। आप हमेशा अपना खुद का निर्माण कर सकते हैं, हालांकि, वही काम करके ConcurrentQueue<T> करता है (एक स्नैपशॉट पर पुनरावृत्त)।

+0

पूरा जवाब, धन्यवाद! शायद आप जानते हैं कि ConcurrentQueue और ConcurrentStack स्नैपशॉट कैसे लेते हैं? क्या वे पूरे संग्रह को एक नई वस्तु में कॉपी करते हैं और प्रतिलिपि बनाते हैं? या उनके पास स्नैपशॉट लेने का कोई और स्मार्ट तरीका है? – tytyryty

5

इस व्यवहार को समर्थन देने के लिए कुछ जटिल जटिल आंतरिक हैंडलिंग की आवश्यकता है, इसलिए अधिकांश संग्रह इस का समर्थन नहीं करते हैं (मुझे Concurrent नामस्थान के बारे में निश्चित नहीं है)।

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

आप आसानी से इस तरह एक संग्रह को लागू कर सकते हैं, या आप (नहीं .NET 4.0 का एक मानक हिस्सा हालांकि) FSharp.Core.dll से FSharpList<T> उपयोग कर सकते हैं:

open Microsoft.FSharp.Collections; 

// Create immutable list from other collection 
var list = ListModule.OfSeq(anyCollection); 
// now we can use `GetEnumerable` 
var en = list.GetEnumerable(); 

// To modify the collection, you create a new collection that adds 
// element to the front (without actually copying everything) 
var added = new FSharpList<int>(42, list); 

अपरिवर्तनीय संग्रह का लाभ यह है कि आप के साथ काम कर सकते हैं उन्हें मूल प्रतिबिंबित किए बिना (प्रतियां बनाकर), और इसलिए जो व्यवहार आप चाहते थे वह "मुफ्त में" है। अधिक जानकारी के लिए, great series by Eric Lippert है।

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