c# - कोशिश क्यों करें{...} अंत में{...} अच्छा; कोशिश करें{...} पकड़{} बुरा?




.net exception-handling (14)

"अंत में" एक बयान है "यह सुनिश्चित करने के लिए आपको हमेशा कुछ करना होगा कि प्रोग्राम राज्य सचेत है"। ऐसे में, यदि कोई संभावना है कि अपवाद प्रोग्राम स्थिति को फेंक सकता है, तो यह हमेशा एक अच्छा फॉर्म है। यह सुनिश्चित करने के लिए कि आपका अंत कोड चलाया गया है, संकलक भी बहुत अधिक समय तक चलता है।

"कैच" एक बयान है "मैं इस अपवाद से पुनर्प्राप्त कर सकता हूं"। आपको केवल उन्हीं अपवादों से पुनर्प्राप्त करना चाहिए जिन्हें आप वास्तव में सही कर सकते हैं - बिना तर्क के पकड़ लें "अरे, मैं कुछ भी ठीक कर सकता हूं!", जो लगभग हमेशा असत्य है।

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

मैंने लोगों को यह कहते हुए देखा है कि किसी भी तर्क के साथ पकड़ का उपयोग करने के लिए यह खराब रूप है, खासकर यदि वह पकड़ कुछ भी नहीं करती है:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

हालांकि, यह अच्छा रूप माना जाता है:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

जहां तक ​​मैं कह सकता हूं, आखिरकार ब्लॉक में क्लीनअप कोड डालने और कोशिश करने के बाद क्लीनअप कोड डालने के बीच एकमात्र अंतर है। यदि आपके पास अपने प्रयास ब्लॉक में वापसी विवरण हैं (उस स्थिति में, अंत में क्लीनअप कोड अंत में होगा भागो, लेकिन प्रयास के बाद कोड .. पकड़ नहीं होगा)।

अन्यथा, अंत में इतना खास क्या है?


अपवाद को फिर से उखाड़ फेंकने के लिए कैच क्लॉज जोड़ने का बुरा अभ्यास है।


आखिरकार वैकल्पिक है - साफ करने के लिए कोई संसाधन नहीं होने पर "अंत में" ब्लॉक होने का कोई कारण नहीं है।


आखिरकार, आप संसाधनों को साफ कर सकते हैं, भले ही आपका कैच स्टेटमेंट कॉलिंग प्रोग्राम तक अपवाद फेंकता हो। खाली उदाहरण के साथ आपके उदाहरण के साथ, थोड़ा अंतर है। हालांकि, अगर आपके पकड़ में, आप कुछ प्रसंस्करण करते हैं और त्रुटि फेंकते हैं, या यहां तक ​​कि केवल एक पकड़ भी नहीं है, अंत में अभी भी दौड़ जाएगा।


एक पठनीयता परिप्रेक्ष्य से, यह स्पष्ट रूप से भावी कोड-पाठकों को बता रहा है "यहां यह सामान महत्वपूर्ण है, इससे कोई फर्क नहीं पड़ता कि क्या होता है।" यह अच्छा है।

इसके अलावा, खाली पकड़ बयान में उनके लिए एक निश्चित "गंध" होती है। वे एक संकेत हो सकते हैं कि डेवलपर्स विभिन्न अपवादों के बारे में सोच नहीं रहे हैं जो उन्हें हो सकता है और उन्हें कैसे संभाला जा सकता है।


कोशिश करें .. आखिरकार ब्लॉक अभी भी उठाए गए अपवादों को फेंक देगा। finally यह सुनिश्चित करता है कि अपवाद फेंकने से पहले क्लीनअप कोड चलाया जाए।

एक खाली पकड़ के साथ प्रयास करें ... पूरी तरह से किसी भी अपवाद का उपभोग करेगा और यह तथ्य छुपाएगा कि यह हुआ। पाठक बंद हो जाएगा, लेकिन सही बात होने पर कोई बात नहीं है। क्या होगा यदि आपका इरादा मुझे फाइल में लिखना था? इस मामले में, आप इसे कोड के उस हिस्से में नहीं बनाएंगे और myfile.txt खाली हो जाएगा। क्या सभी डाउनस्ट्रीम विधियां इसे ठीक से संभालती हैं? जब आप खाली फ़ाइल देखते हैं, तो क्या आप सही ढंग से अनुमान लगा सकते हैं कि यह खाली है क्योंकि एक अपवाद फेंक दिया गया था? अपवाद फेंकने के लिए बेहतर है और यह ज्ञात है कि आप कुछ गलत कर रहे हैं।

एक और कारण यह है कि कोशिश की गई .. इस तरह से किया गया पूरी तरह से गलत है। ऐसा करके आप क्या कह रहे हैं, "कोई फर्क नहीं पड़ता कि क्या होता है, मैं इसे संभाल सकता हूं।" Exception बारे में क्या, क्या आप इसके बाद साफ कर सकते हैं? OutOfMemoryException बारे में क्या? आम तौर पर, आपको केवल उन अपवादों को संभालना चाहिए जिन्हें आप उम्मीद करते हैं और जानते हैं कि कैसे संभालें।


कोशिश करें {...} पकड़ {} हमेशा बुरा नहीं है। यह एक आम पैटर्न नहीं है, लेकिन जब मैं थ्रेड के अंत में एक (संभवतः) खुले सॉकेट को बंद करने की तरह, संसाधनों को बंद करने की आवश्यकता होने पर मुझे इसका उपयोग करने की ज़रूरत होती है।


क्योंकि जब वह एक पंक्ति एक अपवाद फेंकता है, तो आप इसे नहीं जान पाएंगे।

कोड के पहले ब्लॉक के साथ, अपवाद को अवशोषित कर दिया जाएगा, कार्यक्रम की स्थिति गलत होने पर भी प्रोग्राम निष्पादित करना जारी रहेगा।

दूसरे ब्लॉक के साथ, अपवाद फेंक दिया जाएगा और बुलबुले होंगे लेकिन reader.Close()reader.Close() अभी भी चलाने की गारंटी है।

यदि किसी अपवाद की अपेक्षा नहीं की जाती है, तो कोशिश करें .. कैच ब्लॉक को बस इतना न करें, प्रोग्राम खराब स्थिति में जाने पर बाद में डीबग करना मुश्किल होगा और आपको कोई विचार नहीं है कि क्यों।


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


बड़ा अंतर यह है कि try...catch अपवाद को निगल देगा, इस तथ्य को छिपाएगा कि एक त्रुटि हुई। try..finally आपका क्लीनअप कोड चलाएगा और फिर अपवाद जारी रहेगा, जिसे कुछ पता चल जाएगा कि इसके साथ क्या करना है।


यदि आप प्रोग्रामर के लिए सी # पढ़ेंगे तो आप समझेंगे कि आखिरकार ब्लॉक एक एप्लिकेशन को अनुकूलित करने और मेमोरी रिसाव को रोकने के लिए डिज़ाइन किया गया था।

सीएलआर पूरी तरह से लीक को खत्म नहीं करता है ... अगर प्रोग्राम अनजाने में अवांछित वस्तुओं के संदर्भ रखता है तो मेमोरी लीक हो सकती है

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

catch finally में finally अलग था कि पकड़ने के लिए आपको डिजाइन को स्वयं को संभालने / प्रबंधित करने या समझने का तरीका देने के लिए डिज़ाइन किया गया था। इसके बारे में सोचें जो आपको बताता है "अरे मैंने कुछ बुरे लोगों को पकड़ा, तुम मुझे उनके साथ क्या करना चाहते हो?" जबकि finally यह सुनिश्चित करने के लिए डिज़ाइन किया गया था कि आपके संसाधन ठीक से रखा गया था। किसी के बारे में सोचें कि कुछ बुरे लोग हैं या नहीं, वह यह सुनिश्चित करेगा कि आपकी संपत्ति अभी भी सुरक्षित है।

और आपको उन दोनों को अच्छे से काम करने की अनुमति देनी चाहिए।

उदाहरण के लिए:

try
{
  StreamReader reader=new  StreamReader("myfile.txt");
  //do other stuff
}
catch(Exception ex){
 // Create log, or show notification
 generic.Createlog("Error", ex.message);
}
finally   // Will execute despite any exception
{
  reader.Close();
}

यदि आपको नहीं पता कि किस अपवाद प्रकार को पकड़ना है या इसके साथ क्या करना है, तो कैच स्टेटमेंट करने में कोई बात नहीं है। आपको इसे एक उच्च-कॉलर कॉलर के लिए छोड़ देना चाहिए, जिसमें स्थिति के बारे में अधिक जानकारी हो सकती है कि क्या करना है।

अपवाद होने पर आपको अभी भी अंत में एक बयान देना चाहिए, ताकि कॉलर को उस अपवाद को फेंकने से पहले संसाधनों को साफ कर सकें।


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

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


here से लिया गया: here

एक विधि के सफल निष्पादन के हिस्से के रूप में अपवादों को उठाना और पकड़ना नियमित रूप से नहीं होना चाहिए। कक्षा पुस्तकालयों का विकास करते समय, क्लाइंट कोड को ऑपरेशन करने से पहले एक त्रुटि स्थिति का परीक्षण करने का मौका दिया जाना चाहिए जिसके परिणामस्वरूप अपवाद उठाया जा सकता है। उदाहरण के लिए, System.IO.FileStream एक CanRead प्रॉपर्टी प्रदान करता है जिसे रीड विधि को कॉल करने से पहले चेक किया जा सकता है, जो संभावित कोड अपवाद को रोकता है, जैसा कि निम्न कोड स्निपेट में दिखाया गया है:

स्ट्रीम के रूप में मंद स्ट्र = GetStream () यदि (str.CanRead) फिर 'धारा अंत पढ़ने के लिए कोड अगर

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

"प्रभाव तक चलने" कोडिंग तकनीक का उपयोग करने वाले प्रदर्शन प्रभाव को स्पष्ट करने के लिए, कास्ट का प्रदर्शन, जो कि कास्ट विफल होने पर अमान्य कैस्टएक्सप्शन फेंकता है, की तुलना सी # से ऑपरेटर के रूप में की जाती है, जो कि कास्ट विफल होने पर नल लौटाती है। दो तकनीकों का प्रदर्शन उस मामले के लिए समान है जहां कास्ट मान्य है (टेस्ट 8.05 देखें), लेकिन जिस स्थिति में कास्ट अमान्य है, और एक कास्ट का उपयोग करके अपवाद का कारण बनता है, कास्ट का उपयोग करके 600 गुना धीमा होता है ऑपरेटर के रूप में (टेस्ट 8.06 देखें)। अपवाद-फेंकने तकनीक के उच्च प्रदर्शन प्रभाव में अपवाद आवंटित करने, फेंकने और अपवाद को पकड़ने और अपवाद वस्तु के बाद के कचरा संग्रह की लागत शामिल है, जिसका अर्थ यह है कि अपवाद फेंकने का तात्कालिक प्रभाव यह उच्च नहीं है। चूंकि अधिक अपवाद फेंक दिए जाते हैं, अक्सर कचरा संग्रह एक मुद्दा बन जाता है, इसलिए एक अपवाद के लगातार उपयोग के समग्र प्रभाव- कोडिंग तकनीक फेंकना परीक्षण 8.05 के समान होगा।







try-catch-finally