2012-07-19 7 views
10

मैंने फ़ंक्शन में LINQ क्वेरी के परिणाम लौटने पर Collection was modified; enumeration operation may not execute त्रुटियों के कुछ मामलों में भाग लिया है ... (मुझे फ़ंक्शन को इंटरफ़ेस के कार्यान्वयन के रूप में जोड़ना चाहिए और परिणाम इस मॉड्यूल को छोड़ दें किसी अन्य रूप में प्रयोग की जाने वाली।)क्या मुझे हमेशा कॉल करना चाहिए। LINQ क्वेरी परिणामों पर ToArray फ़ंक्शन में लौटाया गया है?

Public Function GetTheFuzzyFuzzbuzzes() As IEnumerable(of FuzzBuzz) _ 
    Implements IFoo.GetTheFuzzyFuzzBuzzes 

    Return mySecretDataSource.Where(Function(x) x.IsFuzzy) 
End Function 

मैं, एक नियम के रूप में, हमेशा .ToArray बुलाना चाहिए जब एक समारोह या संपत्ति गेटर में LINQ क्वेरी का परिणाम लौटने अगर अंतर्निहित डेटा संभावित परिवर्तित करने की है? मुझे पता है कि ऐसा करने में थोड़ा सा दक्षता है, लेकिन मुझे लगता है कि यह सुरक्षित करने की बात है, और इस प्रकार अस्थायी युग्मन मुद्दों से बचने के लिए हमेशा किया जाना चाहिए।

संपादित करें:

मुझे समस्या डोमेन समझा एक बेहतर काम करते हैं।

हमारे पास चिंता के हमारे मुख्य क्षेत्र का ग्राफ आधारित कार्यान्वयन है, जो एक अनुकूलन समस्या है। इकाइयों को ग्राफ नोड्स के रूप में दर्शाया जाता है। विभिन्न लागतों और अन्य मापदंडों के साथ भारित एज नोड्स के बीच संबंध व्यक्त करते हैं। चूंकि उपयोगकर्ता डेटा का उपयोग करता है, हम अलग-अलग किनारों का निर्माण करते हैं और वर्तमान विकल्प के खिलाफ विभिन्न विकल्पों का मूल्यांकन करते हैं ताकि वे प्रत्येक विकल्प के परिणामों पर प्रतिक्रिया दे सकें। अन्य उपयोगकर्ताओं और कार्यक्रमों द्वारा सर्वर पर डेटा में किए गए परिवर्तन को पुश प्रौद्योगिकी के माध्यम से तुरंत क्लाइंट को प्रचारित किया जाता है। हम बहुत सारे थ्रेडिंग का उपयोग करते हैं ...

... इसका मतलब यह है कि हमारे पास बहुत ही अतुल्यकालिक तरीके से बहुत सी चीजें हो रही हैं।

हमारा कार्यक्रम एक अनुबंध परियोजना और एक हल-पर-रन-टाइम कार्यान्वयन परियोजना के साथ मॉड्यूल (एकल जिम्मेदारी सिद्धांत के आधार पर) में विभाजित है, जिसका अर्थ है कि हम इंटरफेस पर भारी निर्भर हैं। हम आम तौर पर IENumerable का उपयोग कर मॉड्यूल के बीच डेटा पास करते हैं (क्योंकि वे अपरिवर्तनीय प्रकार के हैं)।

+1

क्या आप एक प्रोग्राम के छोटे, संकलित-सक्षम संस्करण को पोस्ट कर सकते हैं जो इसे पुन: उत्पन्न करता है? –

+0

दुर्भाग्यवश हमारे कोड-बेस 68 परियोजनाओं के साथ 50000+ एलओसी की तरह है, इसलिए एक अच्छा उदाहरण तैयार करना कठिन होगा। प्रश्न में विस्तारित विवरण देखें। –

उत्तर

5

के बजाय नहीं, मैं इस का एक नियम नहीं होगा जैसा लगता है।

मैं आपकी चिंता को समझता हूं। कॉलिंग पक्ष को पता नहीं हो सकता है कि यह क्रियाएं क्वेरी के परिणामों को प्रभावित करती हैं।

कुछ मामलों में जहां तुम सच में ऐसा नहीं कर सकते हैं:

  • ऐसे अनंत enumerables साथ के रूप में उदाहरण हैं, जहां ऐसा करने स्मृति से बाहर होने का कारण होगा, कर रहे हैं, या प्रगणक में है कि एक नव पैदा करता है प्रत्येक पुनरावृत्ति छवि गणना की। (मेरे पास दोनों हैं)।
  • यदि आप अपने प्रश्नों पर Any() या First() का उपयोग करते हैं। दोनों को केवल पहले तत्व को पढ़ने की आवश्यकता है। अन्य सभी काम व्यर्थ में किया जाता है।
  • यदि आप अनुमान लगाते हैं कि अंकुरित पाइप/फ़िल्टर के साथ जंजीर हो। मध्यवर्ती परिणामों को भौतिक बनाना केवल अतिरिक्त लागत है।

दूसरी ओर, कई मामलों में यह एक सरणी में क्वेरी अमल में लाना करने के लिए जब यह कल्पना है कि सरणी के उपयोग के साइड इफेक्ट है कि क्वेरी को प्रभावित करेगा होगा सुरक्षित है।

सॉफ़्टवेयर लिखते समय यह नियमों के लिए अपील करता है कि "जब आपको एक्स और वाई के बीच चयन करने की आवश्यकता होती है, तो हमेशा एक्स करें"। मुझे विश्वास नहीं है कि ऐसे कोई नियम हैं। शायद 15% में आपको वास्तव में एक्स करना चाहिए, 5% में आपको निश्चित रूप से वाई करने की आवश्यकता है, और शेष मामलों के लिए, इससे कोई फर्क नहीं पड़ता।

शेष 80% के लिए, कुछ भी नहीं करना उचित बात हो सकती है। यदि आप हर जगह ToArray() डालते हैं, तो कोड गलत तरीके से सुझाव देता है कि ऐसा करने का एक कारण था।

+0

+1 के लिए व्यक्तिगत है "कोड गलत तरीके से सुझाव देता है कि ऐसा करने का एक कारण था"।जब कोड की एक पंक्ति लिखी जाती है, तो इसे हटाने के लिए कोई भी सुरक्षित नहीं होगा। समय के साथ-साथ स्पेगेटी कोड में अक्सर इसका परिणाम होता है। – Johnny5

2

यदि आप एक आईनेमरेबल (या IQueryable, या कुछ भी जो स्वयं निहित नहीं है) वापस करने जा रहे हैं, तो इसे कब कहा जा सकता है, इसके साथ क्या किया जा सकता है या यह कितना समय तक कर सकता है स्पष्ट रूप से वर्तनी की आवश्यकता पर आयोजित किया जाना चाहिए।

उन कारणों से, मैं IEnumerable<FuzzBuzz> के बजाय FuzzBuzz[] लौटने की अनुशंसा करता हूं यदि यह किसी प्रकार का (यानी परतों के बीच) का एपीआई है। यदि यह कक्षा/मॉड्यूल के आंतरिक कार्यान्वयन का हिस्सा है, तो देरी-मूल्यांकन IEnumerable<FuzzBuzz> को उचित ठहराना आसान है, लेकिन सरणी का उपयोग करने के लिए अभी भी उचित है।

जब तक कि परिणामों की संख्या बड़ी नहीं होती है, या इसे अक्सर कहा जाता है, यह प्रदर्शन की संभावना होने की संभावना नहीं है (कई परिदृश्यों में, CPU समय सस्ता है, और सरणी को आवंटित स्मृति को बहुत लंबे समय तक नहीं रखा जाएगा)।

+0

का उल्लेख किया जाना चाहिए कि कुछ परिस्थितियों में (जैसे एनएचबीर्नेट के लिंक कार्यान्वयन), आईईयूमेरेबल को आईनेमेरेबल पर निहित रूप से कास्टिंग करने के लिए क्वेरी का कारण बन जाएगा। – rossisdead

+0

मुझे यह उल्लेख पसंद है कि वापसी का प्रकार एक एपीआई निर्णय होना चाहिए। मुझे लगता है कि हम में से बहुत से लोग हैं जो एपीआई के बारे में सोचने में नाकाम रहे हैं जो हम अपने साथियों पर आ रहे हैं। –

5

सामान्य रूप से आपको हमेशा कॉल .ToArray या .ToList LINQ क्वेरी के परिणाम लौटने पर कॉल नहीं करना चाहिए।

.ToArray और .ToList दोनों "लालची" (आलसी के विपरीत) संचालन हैं जो वास्तव में आपके डेटा के स्रोत के लिए क्वेरी करते हैं। और उन्हें कॉल करने के लिए उपयुक्त स्थान और समय वास्तुकला निर्णय हैं। उदाहरण के लिए आप डेटा एक्सेस लेयर के अंदर सभी linq प्रश्नों को पूरा करने के लिए अपने प्रोजेक्ट में एक नियम स्थापित कर सकते हैं, और इस प्रकार वहां सभी डेटा परत अपवाद को संभाल सकते हैं। या जब तक यह संभव हो तब तक उन्हें निष्पादित नहीं किया जाता है और केवल अंत में आवश्यक डेटा प्राप्त होता है। और इस विषय से संबंधित कई अन्य विवरण हैं।

लेकिन अपने फ़ंक्शन से परिणाम लौटने पर .ToArray पर कॉल करने के लिए कॉल करने के लिए, या यह कॉल नहीं है - यह कोई प्रश्न नहीं है और जब तक आप अधिक विस्तृत नमूना प्रस्तुत नहीं करते हैं तब तक इसका कोई जवाब नहीं है।

+0

मैंने प्रश्न में अधिक जानकारी दी है (हालांकि विस्तृत कोड नमूना नहीं है), यदि आप अपना उत्तर अपडेट करना चाहते हैं ... –

+0

मुख्य बिंदु _our प्रोग्राम मॉड्यूल में विभाजित है (** एकल जिम्मेदारी सिद्धांत के आधार पर * *) _ - क्या आप मिश्रण नहीं करना चाहते हैं और आप _data access_ और _graph के हमारे मुख्य क्षेत्र के _graph आधारित कार्यान्वयन को विभाजित करने के लिए कैसे जा रहे हैं? और यह जवाब प्रत्येक परियोजना – Akim

2

"एक नियम के रूप में", नहीं, आपको हमेशा ToList/ToArray को कॉल नहीं करना चाहिए। अन्यथा, myData.GetSomeSubset().WhereOtherCondition().Join(otherdata) जैसे प्रश्न प्रत्येक जंजीर कॉल के लिए अस्थायी बफर आवंटित करने का एक गुच्छा खर्च करते हैं। लेकिन LINQ अपरिवर्तनीय संग्रह के साथ सबसे अच्छा काम करता है। आप उस बिंदु पर अधिक सावधान रहना चाहेंगे जहां आप mySecretDataSource संशोधित करते हैं।

विशेष रूप से, अगर आपके कोड हमेशा अपने डेटा स्रोत के लगातार संशोधन के आसपास संरचित है, कि एक अच्छा कारण बेसब्री से एक सरणी वापस जाने के लिए एक IEnumerable

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