2016-03-04 5 views
5

IEnumerable<> लौटने की विधि में, मैं संसाधन पर खोल रहा हूं और लूपिंग कर रहा हूं (उदा। डेटाबेस पंक्ति पाठक)। एक बार लूप समाप्त हो जाने के बाद, संसाधन फिर से बंद हो जाता है।मैं एक आईनेमरेबल को कैसे रद्द कर सकता हूं?

हालांकि, ऐसा हो सकता है कि कॉलर गणना समाप्त न करने का निर्णय लेता है। यह संसाधन खुला रहता है।

उदाहरण:

IEnumerable<Foo> Bar() 
{ 
    using (var r = OpenResource()) { 
     while (r.Read()) { 
      yield return r; 
     } 
    } 
} 

// OK - this closes the resource again 
foreach (var foo in Bar()) { 
    Console.WriteLine (foo); 
} 

// Not OK - resource stays open! 
Console.WriteLine (Bar().First()); 

मैं इस का समाधान होगा? क्या मैं आसानी से एक गणना रद्द कर सकता हूं, यानी इसे बाकी लूप पर छोड़ने के लिए कहें, या इसे निपटाना (Dispose में सफाई कोड डालना)?

मुझे Func<Result, bool> लौटने पर विचार किया गया ताकि उपयोगकर्ता इसे false वापस कर सकें यदि वह पुनरावृत्ति के साथ किया गया हो। इसी प्रकार, कुछ प्रकार के रद्द टोकन का भी उपयोग किया जा सकता है। लेकिन दोनों दृष्टिकोण मेरे लिए बोझिल लगते हैं।

+1

मैंने खोजा और कोई समान प्रश्न नहीं मिला, हालांकि मुझे यकीन है कि एक होना चाहिए - यह एक बहुत ही बुनियादी सवाल आईएमओ है। – mafu

+5

'ब्रेक; 'इसे रद्द करना चाहिए और जेनरेट कोड को गणनाकर्ता का निपटान करना चाहिए। अगर स्रोत चीजों को सही तरीके से नहीं करता है, तो उसे निश्चित करने की आवश्यकता है। –

+0

@ डैनियलए। मैं इसे कॉलर स्कोप पर रद्द करना चाहता हूं, न कि गणना विधि के अंदर – mafu

उत्तर

12

सामान्य रूप से इसे IEnumerator<> कि IDisposable लागू करता है, और यदि आप IEnumerator<> की परिभाषा को देखो आपको लगता है कि यह दिखाई देगा:

public interface IEnumerator<out T> : IDisposable, IEnumerator 

foreach बयान सही ढंग से Dispose()IEnumerator<> कि IEnumerable<> से प्राप्त करता है, तो कि:

IEnumerable<SomeClass> res = SomeQuery(); 

foreach (SomeClass sc in res) 
{ 
    if (something) 
     break; 
} 

किसी भी तरह से foreach बाहर निकलने पर (break, एक अपवाद, res स्वाभाविक रूप से परिष्करण), IEnumerator<> के Dispose() को बुलाया जाना चाहिए। foreach कैसे कार्यान्वित किया जाता है का एक उदाहरण के लिए https://msdn.microsoft.com/en-us/library/aa664754(v=vs.71).aspx देखें (एक try ... finally ... एक Dispose() अंदर finally के साथ)

ध्यान दें कि सी # using एक yield समारोह के अंदर इस्तेमाल के लिए 'सही' कोड का उत्पादन करेगा। उदाहरण यहाँ देखें: http://goo.gl/Igzmiz

public IEnumerable<Foo> Bar() 
{ 
    using (var r = OpenResource()) 
    { 
     while (r.Read()) 
     { 
      yield return new Foo(); 
     } 
    } 
} 

कुछ है कि

void IDisposable.Dispose() 
{ 
    int num = this.<>1__state; 
    if (num == -3 || num == 1) 
    { 
     try 
     { 
     } 
     finally 
     { 
      this.<>m__Finally1(); 
     } 
    } 
} 

IEnumerator<> की Dispose() विधि एक m__Finally1 विधि है कि (IDisposable)this.<r>5__1.Dispose(); होगा (जहां 5__1 है rOpenResource() से लौटे) फोन करेगा में बदल जाती है। m__Finally भी कहा जाता है, तो कोड बस "बाहर निकालता है" while (r.Read()):

if (!this.<r>5__1.Read()) 
{ 
    this.<>m__Finally1(); 

अगर वहाँ एक अपवाद है और/या।

catch 
{ 
    this.System.IDisposable.Dispose(); 
संबंधित मुद्दे