2011-09-30 19 views
9

चलो पढ़ना चलो कहते हैं कि मैं कुछ कोड है:एक IEnumerable कई बार

var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20); 
int sum1 = items.Sum(x => x.SomeFlag == true); 

और उदाहरण के लिए मैं बाद में कोड में आइटम संग्रह से कुछ अन्य राशि की जरूरत है।

int sum2 = items.Sum(x => x.OtherFlag == false); 

तो मेरा प्रश्न: क्या यह एक बार से अधिक समय तक आईएनयूमेरेबल पर लिंक विधियों को कॉल करना ठीक है? हो सकता है कि मुझे समीक्षक पर रीसेट() विधि को कॉल करना चाहिए या ToList विधि का उपयोग करके आइटम से सूची बनाना चाहिए?

उत्तर

16

अच्छा, यह वास्तव में निर्भर करता है कि आप क्या करना चाहते हैं। आप क्वेरी दो बार को क्रियान्वित करने के हिट ले सकता है (और कि का सही अर्थ क्या पर GetAllItems() करता निर्भर करेगा), या आप किसी सूची में परिणाम को कॉपी करने की हिट ले सकता है: यह है एक बार

var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20).ToList(); 

एक सूची में, जाहिर है कि उस सूची में कई बार फिर से शुरू करने में कोई समस्या नहीं है।

ध्यान दें कि आप Reset पर कॉल नहीं कर सकते क्योंकि आपके पास इटरेटर नहीं है - आपके पास IEnumerable<T> है। मैं वैसे भी IEnumerator<T> को सामान्य रूप से कॉल करने की अनुशंसा नहीं करता - कई कार्यान्वयन (इटरेटर ब्लॉक से सी # कंपाइलर द्वारा उत्पन्न किसी भी समेत) वास्तव में Reset को लागू नहीं करते हैं (यानी वे अपवाद फेंकते हैं)।

1

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

+0

यह एक नहीं है सवाल का जवाब, जो था "क्या यह एक से अधिक बार IENumerable पर लिंक विधियों को कॉल करना ठीक है?" ... जवाब न है"। –

+0

खैर, क्या "ठीक" मतलब थोड़ा अस्पष्ट है। हालांकि आप कई बार एक सूची में फिर से शुरू कर सकते हैं। मैं अपने जवाब में इस के ramifications का जिक्र है। उन पर पुन: प्रयास करना ठीक नहीं है? यदि आप ऐसा सोचते हैं तो अपना स्वयं का उत्तर पोस्ट करें (हालांकि पहले से ही एक स्वीकृत उत्तर है)। –

+0

यह बिल्कुल स्पष्ट है। 'आइटम' एक आईनेमरेबल है, एक सूची नहीं है, और आप इसे केवल एक बार पार कर सकते हैं। एक और जवाब पोस्ट करने की कोई आवश्यकता नहीं है, लेकिन पाठकों के लिए यह समझना महत्वपूर्ण है कि यह गलत है और सवाल पर भी स्पर्श नहीं करता है। –

3

मैं कभी-कभी स्थिति में हूं कि मुझे कई बार एक संख्या को संसाधित करना है। यदि गणना महंगा है, गैर-दोहराने योग्य है और बहुत सारे डेटा उत्पन्न करता है (जैसे डेटाबेस से पढ़ा जाने वाला IQueryable), कई बार गणना करना एक विकल्प नहीं है, न ही परिणाम में स्मृति को बफर कर रहा है।

आज तक मैं अक्सर एग्रीगेटर कक्षाएं लिखता हूं जिसमें मैं फोरैच लूप में वस्तुओं को धक्का दे सकता हूं और आखिरकार परिणाम निकाल सकता हूं - LINQ से बहुत कम सुरुचिपूर्ण है।

लेकिन प्रतीक्षा करें, क्या मैंने अभी "पुश" कहा था? क्या वह आवाज नहीं है ... प्रतिक्रियाशील? तो मैं आज रात की सैर के दौरान सोच रहा था। घर वापस मैंने कोशिश की - और यह काम करता है!

उदाहरण टुकड़ा दिखाता है कि कैसे एक भी पास में पूर्णांक के अनुक्रम से दोनों न्यूनतम और अधिकतम आइटम प्राप्त करने, मानक LINQ ऑपरेटर्स का उपयोग (आरएक्स के उन लोगों के, कि है):

public static MinMax GetMinMax(IEnumerable<int> source) 
{ 
    // convert source to an observable that does not enumerate (yet) when subscribed to 
    var connectable = source.ToObservable(Scheduler.Immediate).Publish(); 

    // set up multiple consumers 
    var minimum = connectable.Min(); 
    var maximum = connectable.Max(); 

    // combine into final result 
    var final = minimum.CombineLatest(maximum, (min, max) => new MinMax { Min = min, Max = max }); 

    // make final subscribe to consumers, which in turn subscribe to the connectable observable 
    var resultAsync = final.GetAwaiter(); 

    // now that everybody is listening, enumerate! 
    connectable.Connect(); 

    // result available now 
    return resultAsync.GetResult(); 
} 
संबंधित मुद्दे