कोशिश करेंगे / अंत में (कैच के बिना) बबल अपवाद?


115

मैं लगभग सकारात्मक हूं कि उत्तर हां है। अगर मैं एक कोशिश अंत में ब्लॉक का उपयोग करें, लेकिन एक पकड़ ब्लॉक का उपयोग नहीं करते हैं तो किसी भी अपवाद बुलबुला होगा। सही बात?

सामान्य तौर पर अभ्यास पर कोई विचार?

सेठ

जवाबों:


130

हाँ, यह बिल्कुल होगा। यह मानकर कि आपका finallyब्लॉक अपवाद नहीं है, निश्चित रूप से, उस मामले में जो मूल रूप से फेंका गया "प्रभावी रूप से" प्रतिस्थापित करेगा।


13
@ डेविड: आप C # में अंततः ब्लॉक से नहीं लौट सकते।
जॉन स्कीट

3
msdn प्रलेखन भी इस जवाब की पुष्टि करता है: वैकल्पिक रूप से, आप उस अपवाद को पकड़ सकते हैं जिसे कोशिश-ब्लॉक स्टेटमेंट में कॉल-स्टैक के उच्चतर स्तर पर फेंका जा सकता है। यही है, आप उस विधि में अपवाद को पकड़ सकते हैं जो उस विधि को कॉल करता है जिसमें कोशिश-अंत में बयान होता है, या उस विधि को कॉल करने वाली विधि में या कॉल स्टैक में किसी भी विधि में। यदि अपवाद नहीं पकड़ा गया है, तो अंत में ब्लॉक का निष्पादन इस बात पर निर्भर करता है कि ऑपरेटिंग सिस्टम अपवाद खोलना ऑपरेशन को ट्रिगर करता है या नहीं।
ब्रॉडबैंड

60

सामान्य तौर पर अभ्यास पर कोई विचार?

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

उस स्थिति में यह यकीनन ऐसा होता है कि आपको अंत में ब्लॉक में कोड नहीं चलाना चाहिए। अंत में ब्लॉक में कोड यह मानकर बनाया जा सकता है कि सबसिस्टम यह निर्भर करता है कि वे स्वस्थ हैं, जब वास्तव में वे गहराई से टूट सकते हैं। अंत में ब्लॉक में कोड चीजों को बदतर बना सकता है।

उदाहरण के लिए, मैं अक्सर इस तरह की चीज देखता हूं:

DisableAccessToTheResource();
try
{
    DoSomethingToTheResource();
}
finally
{
    EnableAccessToTheResource();
}

इस कोड के लेखक सोच रहे हैं "मैं दुनिया के राज्य के लिए एक अस्थायी उत्परिवर्तन बना रहा हूं; मुझे उस राज्य को पुनर्स्थापित करने की आवश्यकता है जो मुझे बुलाया जाने से पहले था"। लेकिन आइए उन सभी तरीकों के बारे में सोचें जो गलत हो सकते हैं।

पहले, संसाधन तक पहुंच कॉलर द्वारा पहले से ही अक्षम हो सकती है; उस स्थिति में, यह कोड इसे फिर से सक्षम करता है, संभवतः समय से पहले।

दूसरा, अगर DoSomethingToTheResource एक अपवाद फेंकता है, तो संसाधन तक पहुंच को सक्षम करने के लिए क्या करना सही है ??? संसाधन का प्रबंधन करने वाला कोड अप्रत्याशित रूप से टूट गया है । यह कोड कहता है, वास्तव में "यदि प्रबंधन कोड टूट गया है, तो सुनिश्चित करें कि अन्य कोड उस टूटे हुए कोड को जितनी जल्दी हो सके कॉल कर सकते हैं, ताकि यह बुरी तरह से भी विफल हो सके ।" यह एक बुरे विचार की तरह लगता है।

तीसरा, अगर DoSomethingToTheResource एक अपवाद फेंकता है, तो हम कैसे जानते हैं कि EnableAccessToTheResource भी अपवाद नहीं फेंकेगा? संसाधन के उपयोग में जो भी गड़बड़ी हुई है, वह भी सफाई कोड को प्रभावित कर सकती है, इस स्थिति में मूल अपवाद खो जाएगा और समस्या का निदान करना कठिन होगा।

मैं कोशिश अंत में ब्लॉक का उपयोग किए बिना इस तरह कोड लिखने के लिए करते हैं:

bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
    DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
    EnableAccessToTheResource();

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

तो आखिरकार ब्लॉक चलाना कब अच्छा होगा? पहला, जब अपवाद अपेक्षित हो। उदाहरण के लिए, आप उम्मीद कर सकते हैं कि किसी फ़ाइल को लॉक करने का प्रयास विफल हो सकता है, क्योंकि किसी और ने इसे लॉक कर दिया है। उस स्थिति में यह अपवाद को पकड़ने और उपयोगकर्ता को रिपोर्ट करने के लिए समझ में आता है। उस मामले में जो टूट गया है उसके बारे में अनिश्चितता कम हो जाती है; आप सफाई करके चीजों को बदतर बनाने की संभावना नहीं है।

दूसरा, जब आप जिस संसाधन की सफाई कर रहे हैं वह एक दुर्लभ प्रणाली संसाधन है। उदाहरण के लिए, अंत में ब्लॉक में फ़ाइल हैंडल को बंद करना समझ में आता है। (ए "का उपयोग करना" बेशक कोशिश-अंत ब्लॉक लिखने का एक और तरीका है।) फ़ाइल की सामग्री भ्रष्ट हो सकती है, लेकिन अब आप इसके बारे में कुछ नहीं कर सकते। फ़ाइल हैंडल अंततः बंद होने जा रहा है, इसलिए यह बाद के बजाय जल्द ही हो सकता है।


7
फिर भी अधिक उदाहरण है कि कैसे हम वास्तव में एक उद्योग के रूप में हमारे कार्य को अभी तक नहीं मिला है जब यह त्रुटि से निपटने के लिए आता है। ऐसा नहीं है कि मेरे पास अपवादों की तुलना में सुझाव देने के लिए कुछ भी बेहतर है, लेकिन मैं उम्मीद कर रहा हूं कि भविष्य में यथोचित आसानी से उठाए जाने वाले कार्य के सही तरीके से आगे बढ़ने की संभावना अधिक होगी।
जॉन स्कीट

Vb.net में, यह जानने के लिए कि अपवाद लंबित है अंत में ब्लॉक में कोड के लिए संभव है। यदि कोई एक अपवाद पदानुक्रम निर्धारित करता है, तो "इसे मत करो; राज्य अन्यथा ठीक है" से "राज्य टूट गया है", एक अंत में केवल तभी ब्लॉक हो सकता है यदि लंबित अपवाद बुरे लोगों में से एक नहीं है। मुझे डिस्पोज़र / क्लीनअप रूटीन अपवादों को पकड़ना पसंद है और एक डिस्पोज़रफ़ेल्डएक्ससेप्शन (जो "खराब" श्रेणी में है, और एक इनर एक्सेप्शन के रूप में मूल अपवाद शामिल है) को फेंकना पसंद है। मैं एक मानक iDisposableEx इंटरफ़ेस को देखने के लिए एक डिस्पोज़ (अपवाद के रूप में) के साथ देखना चाहता हूँ।
सुपरकैट

जबकि मैं सराहना करता हूं कि ऐसे मामले हैं जहां एक अपवाद हो सकता है जबकि एक वस्तु एक खराब स्थिति में है और सफाई का प्रयास चीजों को बदतर बना देगा, मुझे लगता है कि ऐसे मुद्दों को सफाई कोड में संभाला जाना चाहिए, संभवतः प्रतिनिधियों की मदद से। उदाहरण के लिए, एक लॉक रैपर एक "CheckIfSafeToUnlock (Ex के रूप में अपवाद)" फ़ंक्शन प्रतिनिधि को उजागर कर सकता है, जो उस समय सेट किया जा सकता है जब लॉक ऑब्जेक्ट किसी अमान्य स्थिति में हो और अन्यथा साफ़ हो। ताला जारी करने से पहले, रैपर प्रतिनिधि की जांच कर सकता था; यदि गैर-रिक्त है, तो वह इसे चला सकता है और लॉक को केवल तभी जारी कर सकता है जब यह सच हो।
सुपरकैट

एक रैपर का उपयोग करने वाला एक प्रतिनिधि ऐसे कोड की अनुमति देगा जो बाधित होने पर ऑब्जेक्ट क्लीन स्टेट का चयन करने के लिए ऑब्जेक्ट स्टेट में हेरफेर कर सकता है। इस तरह की कार्रवाइयों में डेटा संरचना की मरम्मत और ट्रू लौटाना, एक और "अधिक गंभीर" अपवाद को फेंकना शामिल हो सकता है, जो मूल को लपेटता है, या झूठी वापसी करते समय मूल अपवाद को समाप्त होने देता है।
सुपरकैट

2
एरिक, आपके महान जवाब के लिए धन्यवाद। मुझे लगता है कि मुझे दो प्रश्न पूछने चाहिए क्योंकि आप और जॉन दोनों सही हैं। किसी भी मामले में, आप अपवित्र हैं। सवाल पर ध्यान देने के लिए आपका धन्यवाद।
सेठ स्पीयरमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.