2011-06-03 15 views
8

मुझे निम्नलिखित विषय पर आपकी राय चाहिए:ब्लॉक गैलरी का उपयोग कर?

कल्पना कीजिए कि हमारे पास एक ऐसा तरीका है जो एक विशिष्ट उद्देश्य को प्राप्त करने के लिए ज़िम्मेदार है, लेकिन ऐसा करने के लिए, इसे स्थानीय स्तर पर स्कॉप्ड ऑब्जेक्ट्स की एक महत्वपूर्ण संख्या के समर्थन की आवश्यकता है, कई उनमें से IDisposable लागू करना।

एमएस कोडिंग मानकों का कहना है कि स्थानीय IDisposable ऑब्जेक्ट्स का उपयोग करते समय जिन्हें विधि के दायरे को "जीवित" करने की आवश्यकता नहीं होती है (उदाहरण के लिए कुछ लंबे समय तक रहने वाले object की राज्य जानकारी को आवंटित नहीं किया जाएगा) using निर्माण।

समस्या है, कि कुछ स्थितियों में आप एक नेस्टेड using ब्लॉक के "नरक" प्राप्त कर सकते हैं:

using (var disposableA = new DisposableObjectA()) 
{ 
    using (var disposableB = new DisposableObjectB()) 
    { 
      using (var disposableC = new DisposableObjectC()) 
      { 
       //And so on, you get the idea. 
      } 
    } 
} 

आप किसी भी तरह इस को कम कर सकते हैं अगर वस्तुओं का प्रयोग कर रहे के कुछ एक आम आधार से निकाले जाते हैं या एक सामान्य interface लागू करें जो IDisposable लागू करता है। जब भी आपको ऑब्जेक्ट के सही प्रकार की आवश्यकता होती है तो यह निश्चित रूप से कहा गया ऑब्जेक्ट डालने की लागत पर आता है। कभी-कभी यह लंबे समय के रूप व्यवहार्य हो सकता है के रूप में कास्टिंग की राशि हाथ से नहीं मिलता है:

using (var disposableA = new DisposableObjectA()) 
{ 
    using (DisposableBaseObject disposableB = new DisposableObjectB(), 
      disposableC = new DisposableObjectC) 
    { 
      using (var disposableD = new DisposableObjectD()) 
      { 
       //And so on, you get the idea. 
      } 
    } 
} 

अन्य विकल्प using ब्लॉकों का उपयोग करें और सीधे try-catch ब्लॉक लागू करने के लिए नहीं है। यह इस तरह दिखेगा:

DisposableObjectA disposableA = null; 
DisposableObjectB disposableB = null; 
DisposableObjectC disposableC = null; 
... 

try 
{ 
    disposableA = new DisposableObjectA(); 
    .... 
} 
finally 
{ 
    if (disposableA != null) 
    { 
      disposableA.Dispose(); 
    } 

    if (disposableB != null) 
    { 
      disposableB.Dispose(); 
    } 

    //and so on 
} 

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

तो, सवाल यह है कि: आप किस दृष्टिकोण को बेहतर पसंद करते हैं? क्या यह हमेशा नेस्टेड using ब्लॉक का उपयोग करना बेहतर होता है इससे कोई फर्क नहीं पड़ता कि कितने, या, एक निश्चित सीमा से पहले, try-catch ब्लॉक का उपयोग करना बेहतर है?

+0

सुनिश्चित नहीं हैं कि मैं "नरक" लेकिन एक वैध सवाल +1 – Jodrell

उत्तर

16
सिर्फ एक बयान हो, तो, उदाहरण के लिए

आप कर्ली कोष्ठक की जरूरत नहीं है:

using (var disposableA = new DisposableObjectA()) 
using (var disposableB = new DisposableObjectB()) 
using (var disposableC = new DisposableObjectC()) 
{ 
       //And so on, you get the idea. 
} 

यह हालांकि बाहरी ब्लॉक में हो रहा और कुछ नहीं पर निर्भर करता है।

+0

के रूप में घोंसले का वर्णन होगा यह है कि मैं क्या इस स्थिति में क्या करते हैं। – Gabe

+0

मैंने अक्सर ब्लॉक 2 या 3 स्तरों का उपयोग करके गहराई से लिखा है और सोचा है कि 'बदसूरत लग रहा है'। इसके लिए धन्यवाद - यह उन डीओएच में से एक है! क्षणों। कई डिस्पोजेबल ऑब्जेक्ट्स के लिए –

+0

+1 इस प्रकार जब भी संभव हो तो उन्हें व्यवस्थित करने की उम्मीद है –

7

मुझे लगता है कि आप भूल रहे हैं कि using कथन (कई अन्य लोगों की तरह), आवश्यक रूप से कोड ब्लॉक की आवश्यकता नहीं है, लेकिन एक ही कथन हो सकता है। आपका पहला उदाहरण इस प्रकार लिखा जा सकता है:

using (var disposableA = new DisposableObjectA()) 
using (var disposableB = new DisposableObjectB()) 
using (var disposableC = new DisposableObjectC()) 
{ 
    //And so on, you get the idea. 
} 

मुझे लगता है कि यह समस्या को बहुत आसान बनाता है। ध्यान दें, अगर आपको IDisposable लागू करने वाले उदाहरणों के आविष्कार के बीच कुछ करने की आवश्यकता है, तो इससे मदद नहीं मिलती है।

मैं अब भी अन्य ब्लॉक को घोंसला करने के लिए जाता हूं जो समझ में आता है। foreach एक उदाहरण है।

IEnumerable<int> ints = ...; 

using (var disposableA = new DisposableObjectA()) 
using (var disposableB = new DisposableObjectB()) 
using (var disposableC = new DisposableObjectC()) 
foreach (int i in ints) 
{ 
    // Work with disposableA, disposableB, disposableC, and i. 
} 

यह ध्यान देने योग्य है कि वी.एस. कोड विश्लेषक सही है, जब यह आपको बताता है कि यह ग़लत है:

DisposableObjectA disposableA = null; 
DisposableObjectB disposableB = null; 
DisposableObjectC disposableC = null; 
... 

try 
{ 
    disposableA = new DisposableObjectA(); 
    .... 
} 
finally 
{ 
    if (disposableA != null) 
    { 
      disposableA.Dispose(); 
    } 

    if (disposableB != null) 
    { 
      disposableB.Dispose(); 
    } 

    //and so on 
} 

जब आप using एक दूसरे के ऊपर पर खड़ी उपयोग करें, यह उन्हें एकाधिक try में घोंसले/finally ब्लॉक, इसलिए जैसे:

DisposableObjectA disposableA = null; 
DisposableObjectB disposableB = null; 
DisposableObjectC disposableC = null; 
... 

try 
{ 
    disposableA = new DisposableObjectA(); 

    try 
    { 
     disposableB = new DisposableObjectB(); 

     // Try/catch block with disposableC goes here. 
    } 
    finally 
    { 
     if (disposableB != null) 
     { 
       disposableB.Dispose(); 
     }  
    } 
} 
finally 
{ 
    if (disposableA != null) 
    { 
      disposableA.Dispose(); 
    }  
} 

अपने उदाहरण में, अगर वहाँ एक अपवाद है फेंक दिया जाता है कि जब disposableA.Dispose मार डाला है, तो disposableB और disposableC निपटारा नहीं मिलता (finally ब्लॉक से बाहर निकल गया है), जब disposableB कहा जाता है एक त्रुटि फेंक दिया जाता है, तो disposableC बंद नहीं है, आदि

+0

उत्तर के लिए धन्यवाद! हाँ, मुझे पता है कि कोड विश्लेषक सही है। मेरे मामले में, जब निपटान करते समय ऑब्जेक्ट फेंकना बहुत बुरा होता है (क्योंकि इसे फेंकने के लिए कोई वास्तविक वैध कारण नहीं है)। उस स्थिति में, मैं अधिक नुकसान करने से पहले संभवतः जितना संभव हो सके तेज़ और गहन रूप से बाहर निकलने के लिए बेहतर हूं। – InBetween

+0

@InBetween: हालांकि यह बहुत समझ में नहीं आता है; यदि आपका 'निपटान' कार्यान्वयन विफल हो रहा है, हाँ, यह बुरा है, लेकिन यदि आप अन्य चीजों का निपटान नहीं करते हैं तो यह भी बदतर है। क्या होगा यदि आप ढेर में अपवाद को आगे बढ़ाते हैं और इसे संभालते हैं? अब आपके पास ऐसे संसाधन हैं जिनके पास उनके 'निपटान' विधियों को बुलाया जाना चाहिए था, जो नहीं हैं। – casperOne

1

केवल वास्तविक 'समस्या' के साथ अपने पहला कोड नमूना गहरा घोंसला है, जो कोड को पढ़ने और बनाए रखने में कठोर बना सकता है। अन्य उत्तरों के विकल्प के रूप में आप केवल घुंघराले ब्रेसिज़ को छोड़ने का सुझाव देते हैं, आप सबसे गहराई से घोंसला वाले कोड को एक अलग फ़ंक्शन में दोबारा दोबारा करके इसे गोल कर सकते हैं। यह वास्तव में उनका उपयोग करने से आपकी डिस्पोजेबल वस्तुओं को बनाने और निपटाने की चिंताओं को अलग करता है।

using (var a = new DisposableObjectA()) 
{ 
    using (var b = new DisposableObjectB()) 
    { 
     using (var c = new DisposableObjectC()) 
     { 
       SomeFunction(a,b,c); 
     } 
    } 
} 
+0

दृष्टिकोणों को गठबंधन क्यों न करें, अगर किसी को 'आईडीआईएसओबल' लागू करने वाले 'एन' आइटम की आवश्यकता है, तो उन्हें आपके उदाहरण से एन कोड ब्लॉक की आवश्यकता है; बड़े 'एन' के लिए, जो पठनीयता की समस्या को हल नहीं करता है। – casperOne

+0

हां, उन्हें संयुक्त किया जा सकता है। मुझे लगता है कि लंबे समय से पहले आपको सी बनाने से पहले b.Init() या कुछ कॉल करने की आवश्यकता है, और फिर आपको अचानक अपने घुंघराले ब्रेसिज़ की आवश्यकता है –

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