एक उपयोग ब्लॉक के बीच में लौट रहा है


196

कुछ इस तरह:

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

मेरा मानना ​​है कि यह एक वापसी बयान के लिए उचित जगह नहीं है, क्या यह है?

जवाबों:


194

जैसा कि कई अन्य लोगों ने सामान्य रूप से बताया है कि यह कोई समस्या नहीं है।

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

using ( var x = new Something() ) { 
  // not a good idea
  return x;
}

बस उतना ही बुरा

Something y;
using ( var x = new Something() ) {
  y = x;
}

1
बस मैं आपके द्वारा बताए गए बिंदु के बारे में अपना प्रश्न संपादित करने वाला था। धन्यवाद।
टफा

कृपया मुझे यह समझने में मदद करें कि यह खराब क्यों है। मैं एक स्ट्रीम वापस करना चाहूंगा जिसका उपयोग मैं इमेज प्रोसेसिंग के लिए किसी अन्य फ़ंक्शन में सहायक फ़ंक्शन में कर रहा हूं। ऐसा लगता है कि अगर मैं ऐसा करता हूं तो स्ट्रीम का निपटान किया जाएगा?
बजे जॉन शेडलेटस्की

3
@JohnShedletsky इस मामले में आपके फ़ंक्शन कॉल को उपयोग के साथ लपेटा जाना चाहिए। जैसे की (Stream x = FuncToReturnStream ()) {...} का उपयोग करके और FuncToReturnStream के अंदर कोई उपयोग नहीं करना।
फेलिक्स कील

@JohnShedletsky मुझे यकीन है कि यह इसलिए है क्योंकि returnबयान usingकिसी भी कोड पथ द्वारा ब्लॉक के अंत को दुर्गम बनाता है । usingब्लॉक के अंत को चलाने की जरूरत है ताकि वस्तु को जरूरत पड़ने पर निपटाया जा सके।
फेसपालम

147

यह पूरी तरह से ठीक है।

आप स्पष्ट रूप से यही सोच रहे हैं

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

आँख बंद करके अनुवाद किया जाता है:

IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();

जो, बेशक, एक समस्या होगी, और usingबयान को व्यर्थ बना देगा --- यही वजह है कि यह ऐसा नहीं करता है।

कंपाइलर यह सुनिश्चित करता है कि ब्लॉक को छोड़ने से पहले ऑब्जेक्ट का निपटान किया जाता है - यह ब्लॉक को कैसे छोड़ता है, इसकी परवाह किए बिना।


7
मैं जाहिरा तौर पर था।
तफा

शानदार जवाब @James Curran! लेकिन यह मुझे उत्सुक बनाता है कि यह क्या अनुवाद है। या यह केवल IL में व्यक्त है? (जो मैंने पहले कभी पढ़ने की कोशिश नहीं की है)।
बार्ट

1
@ बर्ट - मैं इसे एक अस्थायी चर में वापसी अभिव्यक्ति का मूल्यांकन करने के रूप में सोचता हूं, फिर निपटान कर रहा हूं, फिर अस्थायी चर वापस कर रहा हूं।
टूलमेकरसेव

@ जेम्स कुरेन ऊपर से यहां, केवल आपने समझाया कि पृष्ठभूमि में क्या हुआ। बहुत धन्यवाद।
सेर्केन टिमोकेन

@ यह संभवत: अनुवाद किया गया है: {{अपना कोड ...} अंत में {x.Dispose (); }
बीप 901

94

यह बिल्कुल ठीक है - कोई समस्या नहीं है। आप क्यों मानते हैं कि यह गलत है?

एक प्रयोग बयान एक कोशिश / अंत में ब्लॉक के लिए बस चीनी है, और के रूप में Grzenio कहते हैं कि यह भी एक कोशिश ब्लॉक से लौटने के लिए ठीक है।

वापसी की अभिव्यक्ति का मूल्यांकन किया जाएगा, फिर अंत में ब्लॉक निष्पादित किया जाएगा, फिर विधि वापस आ जाएगी।


5
जेम्स क्यूरन का जवाब बताता है कि मैं क्या सोच रहा था।
तफा

27

यह पूरी तरह से ठीक काम करेगा, जैसे बीच में लौट रहा हो try{}finally{}


18

यह पूरी तरह से स्वीकार्य है। एक का उपयोग कर बयान IDisposable वस्तु कोई बात नहीं क्या निपटारा किया जाएगा सुनिश्चित करता है।

से MSDN :

उपयोग कथन यह सुनिश्चित करता है कि आप ऑब्जेक्ट पर विधियों को कॉल करते समय भी अपवाद कहते हैं। आप एक कोशिश ब्लॉक के अंदर वस्तु डालकर और फिर अंततः ब्लॉक में डिस्पोज को बुलाकर एक ही परिणाम प्राप्त कर सकते हैं; वास्तव में, यह है कि कंपाइलर द्वारा उपयोग किए गए कथन का अनुवाद कैसे किया जाता है।


14

कोड बलो दिखाता है कि कैसे usingकाम कर रहा है:

private class TestClass : IDisposable
{
   private readonly string id;

   public TestClass(string id)
   {
      Console.WriteLine("'{0}' is created.", id);
      this.id = id;
   }

   public void Dispose()
   {
      Console.WriteLine("'{0}' is disposed.", id);
   }

   public override string ToString()
   {
      return id;
   }
}

private static TestClass TestUsingClose()
{
   using (var t1 = new TestClass("t1"))
   {
      using (var t2 = new TestClass("t2"))
      {
         using (var t3 = new TestClass("t3"))
         {
            return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
         }
      }
   }
}

[TestMethod]
public void Test()
{
   Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}

आउटपुट:

't1' बनाया गया है।
't2' बनाया गया है।
't3' बनाया गया है।
'T1, t2, t3 से निर्मित' बनाया गया है।
't3' का निस्तारण किया जाता है।
't2' का निस्तारण किया जाता है।
't1' का निस्तारण किया जाता है।

निपटाने को वापसी के बयान के बाद बुलाया जाता है, लेकिन फ़ंक्शन के बाहर निकलने से पहले।


1
कृपया ध्यान दें कि कुछ C # ऑब्जेक्ट कस्टम फैशन में
डिस्पोज़ होते हैं

-4

शायद यह 100% सच नहीं है कि यह स्वीकार्य है ...

यदि आप घोंसले के शिकार होने और एक नेस्टेड के भीतर से लौटने वाले होते हैं, तो यह सुरक्षित नहीं हो सकता है।

इसे एक उदाहरण के रूप में लें:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
            return memoryStream.ToArray();
        }
    }
}

मैं एक DataTable में सीएसवी के रूप में आउटपुट किया जा रहा था। बीच में वापसी के साथ, यह सभी पंक्तियों को स्ट्रीम में लिख रहा था, लेकिन आउटपुट सीएसवी हमेशा एक पंक्ति (या एकाधिक, बफर के आकार के आधार पर) को याद कर रहा था। इसने मुझे बताया कि कुछ ठीक से बंद नहीं किया जा रहा था।

सही तरीका यह सुनिश्चित करना है कि पिछले सभी उपयोगों को ठीक से निपटाया जाए:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
        }
    }

    return memoryStream.ToArray();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.