2010-05-16 19 views
24

कभी-कभी मुझे किसी फ़ंक्शन के भीतर कई डिस्पोजेबल ऑब्जेक्ट्स का उपयोग करने की आवश्यकता होती है। सबसे आम मामले में StreamReader और StreamWriter है लेकिन कभी-कभी यह इससे भी अधिक है।नेस्टेड का उपयोग करके (...) कथन

कथन का उपयोग करके नेस्टेड जल्दी से जोड़कर बदसूरत लगते हैं। इसका समाधान करने के लिए मैंने एक छोटी सी कक्षा बनाई है जो IDISposable ऑब्जेक्ट्स एकत्र करता है और जब इसे स्वयं डिस्पोजेक्ट किया जाता है तो उनका निपटान करता है।

public class MultiDispose : HashSet<IDisposable>, IDisposable 
{ 
    public MultiDispose(params IDisposable[] objectsToDispose) 
    { 
     foreach (IDisposable d in objectsToDispose) 
     { 
      this.Add(d); 
     } 
    } 

    public T Add<T>(T obj) where T : IDisposable 
    { 
     base.Add(obj); 
     return obj; 
    } 

    public void DisposeObject(IDisposable obj) 
    { 
     obj.Dispose(); 
     base.Remove(obj); 
    } 


    #region IDisposable Members 

    public void Dispose() 
    { 
     foreach (IDisposable d in this) 
     { 
      d.Dispose(); 
     } 

    } 

    #endregion 
} 

तो मेरी कोड अब इस तरह दिखता है:

 using (MultiDispose md = new MultiDispose()) 
     { 
      StreamReader rdr = md.Add(new StreamReader(args[0])); 
      StreamWriter wrt = md.Add(new StreamWriter(args[1])); 
      WhateverElseNeedsDisposing w = md.Add(new WhateverElseNeedsDisposing()); 

      // code 
     } 

क्या इस दृष्टिकोण है कि सड़क के नीचे समस्याएं पैदा कर सकता के साथ कुछ गलत है? मैंने उद्देश्य पर हैशसेट से विरासत निकाला गया फ़ंक्शन छोड़ दिया ताकि कक्षा अधिक लचीला हो। निश्चित रूप से इस फ़ंक्शन का दुरुपयोग करने से वस्तुएं ठीक से निपटान नहीं हो सकती हैं, लेकिन फिर इस कक्षा के बिना पैर में खुद को शूट करने के कई अन्य तरीके हो सकते हैं।

+0

-1: प्रश्न भी व्यक्तिपरक – Simon

+1

IMO - बस कई स्तरों पर एक बुरा विचार। मुझे उम्मीद है कि आप यहां अपने मार्गदर्शन के लिए मार्गदर्शन करेंगे और किसी भी टीम के सदस्यों के साथ आप काम कर सकते हैं। कुछ स्पष्टता के लिए स्कीट का जवाब देखें। –

+9

@ सिमॉन: मूर्ख मत बनो। हमारे पास हर समय नामकरण, पूंजीकरण और इंडेंटिंग के बारे में प्रश्न हैं। यह तुलना में काफी महत्वपूर्ण है। –

उत्तर

44

तुम बस ऐसा कर सकता है:

using (var a = new A()) 
using (var b = new B()) 
{ 
    /// ... 
} 
+1

मैं केवल एक बार यह टिप्पणी जोड़ूंगा, भले ही तीन लोगों ने एक ही बात कहा हो। यदि आपके कोडिंग मानक के हिस्से के रूप में स्टाइलकॉप है, तो मुझे नहीं लगता कि यह इस तरह होगा क्योंकि यह नियम के गलत हो जाता है जो बिना घुंघराले ब्रेसिज़ – Stewart

+2

डैंग के बिना प्रतिबंध लगाता है! इंटेलिसेन्स की एक भाषा स्वयं से सीखने वाली है!मैंने वर्षों से सी # का उपयोग किया है और इस तरह बयान का उपयोग करके चेनिंग के बारे में सोचा नहीं था :( – Ghostrider

+9

@ स्टार्टकॉप स्टाइलकॉप को यह स्टाइलकॉप पसंद नहीं है, तो गलत है। – Will

12

शायद यह सिर्फ इतना है कि आप एक सरल उदाहरण से पता चला है है, लेकिन मुझे लगता है कि निम्नलिखित अधिक पठनीय है।

using (StreamReader rdr = new StreamReader(args[0])) 
using (StreamWriter wrt = new StreamWriter(args[1])) 
{  
    // code 
} 
6

आप नेस्टेड using बयान केवल ब्रेसिज़ की एक जोड़ी का उपयोग कर, इस तरह से खूबसूरत बना सकते हैं:

using (StreamReader rdr = new StreamReader(args[0])) 
using (StreamWriter wrt = new StreamWriter(args[1])) 
{ 
    ///... 
} 

आपके प्रश्न का उत्तर के लिए, आप इसके अलावा के विपरीत क्रम में निपटान के लिए की जरूरत है ।
इसलिए, आप HashSet का उपयोग नहीं कर सकते हैं।

इसके अलावा, IDisposable एस की बाहरी दुनिया में सूची का खुलासा करने का कोई कारण नहीं है।
इसलिए, आपको किसी भी संग्रह वर्ग का उत्तराधिकारी नहीं होना चाहिए, और इसके बजाय एक निजी List<IDisposable> बनाए रखना चाहिए।

तब आपके पास Add<T> और Dispose विधियां (और कोई अन्य विधियां नहीं), और Dispose में पीछे की सूची के माध्यम से लूप होना चाहिए।

+3

+1 हैशसेट पर शानदार पकड़ ... – Josh

4

व्यक्तिगत रूप से यह मुझे पागल कर देगा। यदि आप कष्टप्रद होने के लिए कथन का उपयोग करके घोंसला ढूंढ रहे हैं, तो आप कोशिश/अंत में वाक्यविन्यास पर वापस जा सकते हैं। निपटान विधियों को अपवादों को फेंकना नहीं चाहिए ताकि आप यह मान सकें कि एकाधिक डिस्पोजेबल को कोशिश/आखिरकार ब्लॉक में व्यक्तिगत रूप से लपेटने की आवश्यकता नहीं होगी।

using (var stream = File.Open(...)) 
using (var reader = new StreamReader(stream)) { 

    // do stuff 

} 
20

सामान्य सिद्धांत के बारे में कुछ अंक:

भी ध्यान देने योग्य है कि आप केवल तरह आसन्न का उपयोग कर ब्लॉक के लिए कोष्ठक के एक सेट की जरूरत है वह यह है कि

  • आपका कोड साफ़ तौर पर गैर मुहावरेदार है सी#। असल में आप किसी और से पूछ रहे हैं जो बहुत कम लाभ के लिए बोर्ड को असामान्य शैली पर लेने के लिए आपके कोड के साथ काम करता है।
  • के रूप में अन्य लोगों ने बताया है, तो आप घोंसला अतिरिक्त ब्रेसिज़ बिना using बयान
  • आप अपने आप को बहुत एक एकल विधि में बयान का उपयोग करने का साथ मिल जाए, आप छोटे तरीकों
  • में तोड़ने विचार करना चाह सकते कर सकते हैं यह मानते हुए कि

    using (Stream input = File.OpenRead("input.dat"), 
         output = File.OpenWrite("output.dat")) 
    { 
    } 
    

अब तुम सच में थी के साथ आगे जाना चाहता हूँ: आप एक ही प्रकार के दो चर है, तो आप एक एकल का उपयोग कर बयान उपयोग कर सकते हैं एस:

  • आपका कोड हार्ड-टू-पूर्वानुमान आदेश में इसके निहित संसाधनों का निपटान करेगा। एक सेट का उपयोग करने के बजाय, इसे एक सूची एम्बेड करना चाहिए - और फिर Add पर कॉल के लिए रिवर्स ऑर्डर में चीजों का निपटान करना चाहिए।
  • वहाँ का कोई कारण नहीं हैHashSet<T> से या वास्तव में किसी भी संग्रह निकाले जाते हैं। आपको में के भीतर एक निजी सदस्य चर के रूप में एक सूची होना चाहिए।
  • तो Dispose कॉल में से एक विफल रहता है, अन्य Dispose कॉल से कोई भी बनाया जाएगा; पारंपरिक using कथन के साथ, Dispose पर प्रत्येक कॉल अपने finally ब्लॉक के भीतर बनाई गई है।

मूल रूप से, मुझे लगता है कि यह एक बुरा विचार है। गहरे दो स्तरों को घोंसले दर्दनाक से दूर है; घोंसले तीन दुर्लभ होना चाहिए; घोंसले चार या अधिक दृढ़ता से रिफैक्टरिंग का सुझाव देता है। गहरी घोंसले के दर्द से निपटने की कोशिश करने के बजाय, आपको इससे दूर डिज़ाइन करना चाहिए।

+1

+1 'बुरा विचार' के लिए +1। मेरी भावनाएं उस अंतर्निहित ब्लॉक में थोड़ी दूर जाती हैं, जब तक कि कोड कभी भी छुआ न जाए, बग होने की प्रतीक्षा कर रहे हैं। मैं हमेशा अपवाद के बिना स्पष्ट ब्लॉक का उपयोग करता हूं। और जैसा कि आप कहते हैं, अगर मुझे घोंसले से परेशान है, तो मैं इससे दूर डिजाइन करता हूं। –

+0

मुझे पूरी तरह से यकीन नहीं है, लेकिन बयानों का उपयोग करने की मेरी समझ का अर्थ है कि एक ही प्रकार के दो चर के आपका उदाहरण असुरक्षित है। मुझे पूरा यकीन है कि दो वस्तुएं शुरुआत के लिए एक-दूसरे पर निर्भर नहीं रहेंगी क्योंकि निर्माण आदेश संभवतः गैर निर्धारक नहीं है, लेकिन यदि दूसरा कन्स्ट्रक्टर फेंकता है, तो मुझे पूरा यकीन है कि पहली वस्तु का निपटारा नहीं किया जाएगा। छोटे तरीकों में तोड़ने का सुझाव देने के लिए – Stewart

+0

+1। इसके अलावा, +1 @ स्की के बिना हमेशा अपवाद के ब्लॉक होने का सुझाव देने के लिए। – Travis

3

मुझे लगता है मैं लोग हैं, जो दूसरे को पसंद करने के बाद बयान से एक का उपयोग करना चाहते हैं के साथ असहमत कहने के लिए मिल गया है:

using (var a = new StreamReader()) 
using (var b = new StreamWriter()) 
{ 
// Implementation 
} 

मेरी राय में, कि बहुत अपठनीय है - कि लिपटे नहीं है कोड के किसी भी ब्लॉक होने सिर्फ खराब शैली है, और इससे समस्याएं पैदा हो सकती हैं जब तक कि इस पर काम करने वाले सभी डेवलपर्स बहुत सावधान नहीं हैं।

मैं बराबर है कि डाल चाहते हैं की तरह कुछ के साथ:

if (someBoolean) DoSomething(); 
{ 
    // Some code block unrelated to the if statement 
} 

तकनीकी तौर पर यह अवैध नहीं है, लेकिन यह को देखने के लिए भयानक है।

मैं मानता हूँ कि MultiDispose अवधारणा शायद नहीं सबसे अच्छा विचार है, तथ्य यह है कि यह एक स्वीकृत पद्धति नहीं है की वजह से है, लेकिन मैं निश्चित रूप से इस मार्ग या तो जाना नहीं होता। यदि आप चीजों को छोटे टुकड़ों में तोड़ नहीं सकते हैं, तो मैं सिर्फ घोंसले के उपयोग के साथ रहने का सुझाव दूंगा।

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