c# - अपवाद हैंडलिंग के लिए प्रयास करने का प्रयास कैसे करें सबसे अच्छा अभ्यास है




.net exception (10)

अपवादों के साथ, मैं निम्नलिखित कोशिश करता हूं:

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

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

कोड में, इस तरह कुछ:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}

मेरे सहयोगी के कोड को तब तक बनाए रखने के लिए जो एक वरिष्ठ डेवलपर होने का दावा करता है, मैं अक्सर निम्नलिखित कोड देखता हूं:

try
{
  //do something
}
catch
{
  //Do nothing
}

या कभी-कभी वे फ़ाइलों को लॉग करने के लिए लॉगिंग जानकारी लिखते हैं जैसे कि try catch ब्लॉक का try catch

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

मैं बस सोच रहा हूं कि उन्होंने जो किया है वह सबसे अच्छा अभ्यास है? यह मुझे उलझन में डाल देता है क्योंकि मेरी सोच में उपयोगकर्ताओं को पता होना चाहिए कि सिस्टम के साथ क्या होता है।

कृप्या मुझे कुछ सलाह दीजिए।


आपको अपवादों के लिए इन डिजाइन दिशानिर्देशों पर विचार करना चाहिए

  • अपवाद फेंकता है
  • मानक अपवाद प्रकार का उपयोग करना
  • अपवाद और प्रदर्शन

https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exceptions


कभी-कभी आपको उन अपवादों का इलाज करने की आवश्यकता होती है जो उपयोगकर्ताओं को कुछ भी नहीं कहते हैं।

मेरा तरीका है:

  • महत्वपूर्ण अपवादों के लिए आवेदन स्तर (यानी global.asax में) पर बिना किसी अपवाद के अपवादों को पकड़ने के लिए (एप्लिकेशन उपयोगी नहीं हो सकता है)। ये निष्कर्ष मैं इस जगह पर नहीं पकड़ रहा हूं। बस उन्हें ऐप स्तर पर लॉग करें और सिस्टम को अपना काम करने दें।
  • "जगह पर" पकड़ें और उपयोगकर्ता को कुछ उपयोगी जानकारी दिखाएं (गलत संख्या दर्ज की गई है, पार्स नहीं कर सकती)।
  • जगह पर पकड़ो और सीमांत समस्याओं पर कुछ भी नहीं करें जैसे "मैं पृष्ठभूमि पर अद्यतन जानकारी की जांच करूंगा, लेकिन सेवा नहीं चल रही है"।

यह निश्चित रूप से सबसे अच्छा अभ्यास नहीं है। ;-)


किसी भी तर्क के बिना catch बस अपवाद खा रहा है और इसका कोई उपयोग नहीं है। अगर कोई घातक त्रुटि होती है तो क्या होगा? अगर आप तर्क के बिना पकड़ का उपयोग करते हैं तो क्या हुआ यह जानने का कोई तरीका नहीं है।

एक कैच स्टेटमेंट को FileNotFoundException जैसे अधिक विशिष्ट अपवादों को पकड़ना चाहिए और फिर अंत में आपको Exception को पकड़ना चाहिए जो किसी अन्य अपवाद को पकड़ लेगा और उन्हें लॉग करेगा।


खाली पकड़ ब्लॉक छोड़ना बुरा काम है। यदि कोई त्रुटि है तो इसे संभालने का सबसे अच्छा तरीका यह है:

  1. इसे फ़ाइल \ डेटाबेस आदि में लॉग इन करें ..
  2. इसे फ्लाई पर ठीक करने का प्रयास करें (शायद उस ऑपरेशन को करने का वैकल्पिक तरीका आज़माएं)
  3. अगर हम इसे ठीक नहीं कर सकते हैं, तो उपयोगकर्ता को सूचित करें कि कुछ त्रुटि है और निश्चित रूप से ऑपरेशन को रोक दें

दूसरा दृष्टिकोण एक अच्छा है।

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

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

मैं अनुशंसा करता हूं कि आप अपने पूरे आवेदन के लिए दूसरे दृष्टिकोण के लिए जाएं।


मुझे पता है कि यह एक पुराना सवाल है, लेकिन यहां किसी ने भी एमएसडीएन लेख का उल्लेख नहीं किया है, और यह वह दस्तावेज था जिसने वास्तव में इसे मेरे लिए साफ़ कर दिया था, एमएसडीएन के पास इस पर एक बहुत अच्छा दस्तावेज है, आपको निम्नलिखित स्थितियों के सत्य होने पर अपवादों को पकड़ना चाहिए:

  • आपको एक अच्छी समझ है कि अपवाद क्यों फेंक दिया जा सकता है, और आप एक विशिष्ट रिकवरी को कार्यान्वित कर सकते हैं, जैसे कि जब आप FileNotFoundException ऑब्जेक्ट को पकड़ते हैं तो उपयोगकर्ता को एक नया फ़ाइल नाम दर्ज करने के लिए संकेत मिलता है।

  • आप एक नया, अधिक विशिष्ट अपवाद बना सकते हैं और फेंक सकते हैं।

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • आप अतिरिक्त हैंडलिंग के लिए इसे पास करने से पहले आंशिक रूप से अपवाद को संभालना चाहते हैं। निम्न उदाहरण में, अपवाद को फिर से फेंकने से पहले एक त्रुटि लॉग में एक प्रविष्टि जोड़ने के लिए एक कैच ब्लॉक का उपयोग किया जाता है।
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

मैं पूरे " अपवाद और अपवाद हैंडलिंग " अनुभाग और अपवादों के लिए सर्वोत्तम अभ्यास पढ़ने का सुझाव दूंगा


मेरी अपवाद हैंडलिंग रणनीति है:

  • Application.ThreadException event को हुक करके सभी अनचाहे अपवादों को पकड़ने के लिए। थ्रेड अपवाद Application.ThreadException event , फिर निर्णय लें:

    • यूआई एप्लिकेशन के लिए: इसे माफी संदेश के साथ उपयोगकर्ता को पॉप करने के लिए (Winforms)
    • किसी सेवा या कंसोल एप्लिकेशन के लिए: इसे किसी फ़ाइल (सेवा या कंसोल) पर लॉग करें

फिर मैं हमेशा कोड के हर टुकड़े को संलग्न करता हूं जो try/catch में बाहरी रूप से चलाया जाता है:

  • विनफॉर्म इंफ्रास्ट्रक्चर (लोड, क्लिक, चयनित चेंज ...) द्वारा निकाली गई सभी घटनाएं
  • सभी घटनाओं को तीसरे पक्ष के घटकों द्वारा निकाल दिया गया

फिर मैं 'कोशिश / पकड़' में संलग्न

  • सभी परिचालन जो मुझे पता है वे हर समय काम नहीं कर सकते हैं (आईओ ऑपरेशंस, संभावित शून्य विभाजन के साथ गणना ...)। इस तरह के मामले में, मैंने वास्तव में क्या हुआ उसका ट्रैक रखने के लिए एक नया ApplicationException("custom message", innerException) फेंक दिया

इसके अतिरिक्त, मैं अपवादों को सही तरीके से सॉर्ट करने के लिए अपना सर्वश्रेष्ठ प्रयास करता हूं। अपवाद हैं जो:

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

    • घटना लॉग में
    • या डिस्क पर एक .log फ़ाइल में

एप्लिकेशन शीर्ष स्तर त्रुटि हैंडलर में अपवादों को संभालने के लिए कुछ स्थिर तरीकों को डिजाइन करना एक अच्छा अभ्यास है।

मैं खुद को भी कोशिश करने के लिए मजबूर करता हूं:

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

तो अंत में:

खराब:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

निकम्मा:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

बिना पकड़ के आखिरकार कोशिश करने के लिए पूरी तरह से वैध है:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

मैं शीर्ष स्तर पर क्या करता हूं:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

मैं कुछ बुलाए गए कार्यों में क्या करता हूं:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

अपवाद हैंडलिंग (कस्टम अपवाद) के साथ बहुत कुछ करना है, लेकिन जो नियम मैं ध्यान में रखने की कोशिश करता हूं वह मेरे द्वारा किए जाने वाले सरल अनुप्रयोगों के लिए पर्याप्त है।

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

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}

सबसे अच्छा अभ्यास त्रुटि होने पर अपवाद को फेंकना है। क्योंकि एक त्रुटि हुई है और इसे छुपाया नहीं जाना चाहिए।

लेकिन वास्तविक जीवन में जब आप इसे छिपाना चाहते हैं तो आपको कई स्थितियां हो सकती हैं

  1. आप तीसरे पक्ष के घटक पर भरोसा करते हैं और आप त्रुटि के मामले में प्रोग्राम जारी रखना चाहते हैं।
  2. आपके पास एक व्यावसायिक मामला है जिसे आपको त्रुटि के मामले में जारी रखने की आवश्यकता है

सबसे अच्छा अभ्यास यह है कि अपवाद हैंडलिंग को कभी भी मुद्दों को छिपाना नहीं चाहिए । इसका मतलब है कि try-catch ब्लॉक बहुत दुर्लभ होना चाहिए।

ऐसी 3 परिस्थितियां हैं जहां एक try-catch का उपयोग करना समझ में आता है।

  1. हमेशा ज्ञात अपवादों के साथ कम-से-कम के रूप में व्यवहार करें। हालांकि, अगर आप अपवाद की उम्मीद कर रहे हैं तो यह आमतौर पर इसके लिए परीक्षण करने के लिए बेहतर अभ्यास है। उदाहरण के लिए पार्स, स्वरूपण और अंकगणितीय अपवाद एक विशिष्ट try-catch बजाय पहले तर्क जांच द्वारा पहले से बेहतर तरीके से संभाले जाते हैं।

  2. यदि आपको अपवाद पर कुछ करने की आवश्यकता है (उदाहरण के लिए लॉगिंग या लेनदेन को वापस रोल करें) तो अपवाद को फिर से फेंक दें।

  3. हमेशा अज्ञात अपवादों के साथ सौदा करें जितना आप कर सकते हैं - एकमात्र कोड जिसे अपवाद का उपभोग करना चाहिए और फिर इसे फेंकना नहीं है, वह यूआई या सार्वजनिक एपीआई होना चाहिए।

मान लें कि आप रिमोट एपीआई से कनेक्ट हो रहे हैं, यहां आप कुछ त्रुटियों की अपेक्षा करना चाहते हैं (और उन परिस्थितियों में चीजें हैं), इसलिए यह मामला 1 है:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

ध्यान दें कि कोई अन्य अपवाद नहीं पकड़ा जाता है, क्योंकि उनकी अपेक्षा नहीं की जाती है।

अब मान लीजिए कि आप डेटाबेस में कुछ सहेजने की कोशिश कर रहे हैं। अगर यह विफल रहता है तो हमें इसे वापस रोल करना होगा, इसलिए हमारे पास केस 2 है:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

ध्यान दें कि हम अपवाद को फिर से फेंक देते हैं - कोड को ऊपर उठाने के लिए अभी भी यह जानने की जरूरत है कि कुछ विफल हो गया है।

आखिरकार हमारे पास यूआई है - यहां हम पूरी तरह से अनचाहे अपवाद नहीं लेना चाहते हैं, लेकिन हम उन्हें छिपाना नहीं चाहते हैं। यहां हमारे पास केस 3 का एक उदाहरण है:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

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

इसका मतलब यह है कि केस 1 (ज्ञात अपवाद) और केस 3 (एक-ऑफ यूआई हैंडलिंग) दोनों में बेहतर पैटर्न हैं (अपेक्षित त्रुटि या यूआई को हाथ से निपटने में हाथ त्रुटि से बचें)।

यहां तक ​​कि मामले 2 को बेहतर पैटर्न द्वारा प्रतिस्थापित किया जा सकता है, उदाहरण के लिए लेनदेन के क्षेत्र (ब्लॉक के दौरान किए गए किसी भी लेनदेन को रोलबैक using ब्लॉक using करना) डेवलपर्स के लिए सर्वोत्तम अभ्यास पैटर्न गलत प्राप्त करना कठिन बनाता है।

उदाहरण के लिए मान लीजिए कि आपके पास बड़े पैमाने पर ASP.Net एप्लिकेशन है। त्रुटि लॉगिंग ELMAH माध्यम से हो सकती है, त्रुटि प्रदर्शन स्थानीय रूप से एक जानकारीपूर्ण वाईएसओडी और उत्पादन में एक अच्छा स्थानीय संदेश हो सकता है। डाटाबेस कनेक्शन सभी लेनदेन के क्षेत्र और ब्लॉक using सकते हैं। आपको एक भी try-catch ब्लॉक try-catch आवश्यकता नहीं है।

टीएल; डीआर: वास्तव में सबसे अच्छा अभ्यास वास्तव में try-catch ब्लॉक का उपयोग नहीं करना है।





try-catch