c# - क्या "फेंक" और "पूर्व फेंक" के बीच कोई अंतर है?




.net exception (7)

(मैंने पहले पोस्ट किया था, और @ मार्क गर्वेल ने मुझे सही किया है)

अंतर का प्रदर्शन यहां दिया गया है:

        static void Main(string[] args) {
        try {
            ThrowException1(); // line 19
        } catch (Exception x) {
            Console.WriteLine("Exception 1:");
            Console.WriteLine(x.StackTrace);
        }
        try {
            ThrowException2(); // line 25
        } catch (Exception x) {
            Console.WriteLine("Exception 2:");
            Console.WriteLine(x.StackTrace);
        }
    }

    private static void ThrowException1() {
        try {
            DivByZero(); // line 34
        } catch {
            throw; // line 36
        }
    }
    private static void ThrowException2() {
        try {
            DivByZero(); // line 41
        } catch (Exception ex) {
            throw ex; // line 43
        }
    }

    private static void DivByZero() {
        int x = 0;
        int y = 1 / x; // line 49
    }

और यहां आउटपुट है:

Exception 1:
   at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49
   at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19

Exception 2:
   at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25

आप देख सकते हैं कि अपवाद 1 में, स्टैक ट्रेस DivByZero() विधि पर वापस चला जाता है, जबकि अपवाद 2 में यह नहीं होता है।

ध्यान दें, हालांकि, ThrowException1() और ThrowException2() में दिखाया गया लाइन नंबर throw स्टेटमेंट की लाइन संख्या है, कि DivByZero() को कॉल की लाइन संख्या, जो शायद अब समझ में आता है कि मैं इसके बारे में सोचता हूं बिट ...

रिलीज मोड में आउटपुट

अपवाद 1:

at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)

अपवाद 2:

at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)

क्या यह केवल मूलभूत स्टैकट्रेस को डीबग मोड में रखता है?

कुछ पोस्ट हैं जो पूछती हैं कि उन दोनों के बीच क्या अंतर है।
(मुझे इसका जिक्र क्यों करना है ...)

लेकिन मेरा सवाल इस तरह से अलग है कि मैं एक और त्रुटि भगवान की तरह हैंडलिंग विधि में "फेंक पूर्व" कह रहा हूं।

public class Program
{
    public static void Main(string[] args)
    {
        try
        {
            // something
        }
        catch (Exception ex)
        {
            HandleException(ex);
        }
    }

    private static void HandleException(Exception ex)
    {
        if (ex is ThreadAbortException)
        {
            // ignore then,
            return;
        }

        if (ex is ArgumentOutOfRangeException)
        {
            // Log then,
            throw ex;
        }

        if (ex is InvalidOperationException)
        {
            // Show message then,
            throw ex;
        }

        // and so on.
    }
}

यदि Main में try & catch , तो मैं throw; उपयोग करूंगा throw; त्रुटि को पुनर्स्थापित करने के लिए। लेकिन उपर्युक्त सरल कोड में, सभी अपवाद हैंडलएक्सप्शन के माध्यम से जाते हैं

throw ex; HandleException अंदर बुलाए जाने पर throw के समान प्रभाव पड़ता है?


अन्य उत्तरों पूरी तरह से सही हैं, लेकिन यह जवाब कुछ अतिरिक्त detalis प्रदान करता है, मुझे लगता है।

इस उदाहरण पर विचार करें:

using System;

static class Program
{
  static void Main()
  {
    try
    {
      ThrowTest();
    }
    catch (Exception e)
    {
      Console.WriteLine("Your stack trace:");
      Console.WriteLine(e.StackTrace);
      Console.WriteLine();
      if (e.InnerException == null)
      {
        Console.WriteLine("No inner exception.");
      }
      else
      {
        Console.WriteLine("Stack trace of your inner exception:");
        Console.WriteLine(e.InnerException.StackTrace);
      }
    }
  }

  static void ThrowTest()
  {
    decimal a = 1m;
    decimal b = 0m;
    try
    {
      Mult(a, b);  // line 34
      Div(a, b);   // line 35
      Mult(b, a);  // line 36
      Div(b, a);   // line 37
    }
    catch (ArithmeticException arithExc)
    {
      Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);

      //   uncomment EITHER
      //throw arithExc;
      //   OR
      //throw;
      //   OR
      //throw new Exception("We handled and wrapped your exception", arithExc);
    }
  }

  static void Mult(decimal x, decimal y)
  {
    decimal.Multiply(x, y);
  }
  static void Div(decimal x, decimal y)
  {
    decimal.Divide(x, y);
  }
}

यदि आप throw arithExc; लाइन, आपका आउटपुट है:

Handling a DivideByZeroException.
Your stack trace:
   at Program.ThrowTest() in c:\somepath\Program.cs:line 44
   at Program.Main() in c:\somepath\Program.cs:line 9

No inner exception.

निश्चित रूप से, आपने उस अपवाद के बारे में जानकारी खो दी है। यदि इसके बजाय आप throw; उपयोग करते हैं throw; लाइन, यह आपको मिलता है:

Handling a DivideByZeroException.
Your stack trace:
   at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
   at System.Decimal.Divide(Decimal d1, Decimal d2)
   at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
   at Program.ThrowTest() in c:\somepath\Program.cs:line 46
   at Program.Main() in c:\somepath\Program.cs:line 9

No inner exception.

यह बहुत बेहतर है, क्योंकि अब आप देखते हैं कि यह Program.Div था। Program.Div विधि जिसने आपको समस्याएं पैदा की थीं। लेकिन यह अभी भी मुश्किल है कि यह समस्या लाइन 35 या रेखा 37 से try ब्लॉक में आता है या नहीं।

यदि आप बाहरी अपवाद में लपेटकर तीसरे विकल्प का उपयोग करते हैं, तो आप कोई जानकारी नहीं खोते हैं:

Handling a DivideByZeroException.
Your stack trace:
   at Program.ThrowTest() in c:\somepath\Program.cs:line 48
   at Program.Main() in c:\somepath\Program.cs:line 9

Stack trace of your inner exception:
   at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
   at System.Decimal.Divide(Decimal d1, Decimal d2)
   at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
   at Program.ThrowTest() in c:\somepath\Program.cs:line 35

विशेष रूप से आप देख सकते हैं कि यह लाइन 35 है जो समस्या का कारण बनती है। हालांकि, लोगों को InnerException खोज करने की आवश्यकता है, और यह सरल मामलों में आंतरिक अपवादों का उपयोग करने के लिए कुछ हद तक अप्रत्यक्ष लगता है।

इस ब्लॉग पोस्ट में वे Exception ऑब्जेक्ट पर internal अंतर्दृष्टि विधि InternalPreserveStackTrace() को कॉल करके (प्रतिबिंब के माध्यम से) लाइन नंबर (कोशिश ब्लॉक की रेखा) को संरक्षित करते हैं। लेकिन इस तरह प्रतिबिंब का उपयोग करना अच्छा नहीं है (.NET Framework बिना किसी चेतावनी के अपने दिन internal सदस्यों को बदल सकता है)।


चलो फेंकने और पूर्व फेंक के बीच अंतर समझते हैं। मैंने सुना है कि कई सामान्य साक्षात्कारों में इस आम पूछा जा रहा है।

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

चलिए एक उदाहरण के साथ समझते हैं।

आइए पहले फेंको समझें।

static void Main(string[] args) {
        try {
            M1();
        } catch (Exception ex) {
            Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
            Console.WriteLine(ex.StackTrace.ToString());
            Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
            Console.WriteLine(ex.TargetSite.ToString());
        }
        Console.ReadKey();
}

static void M1() {
        try {
            M2();
        } catch (Exception ex) {
            throw;
        };
}

static void M2() {
    throw new DivideByZeroException();
}

उपरोक्त का उत्पादन नीचे है।

पूर्ण पदानुक्रम और विधि नाम दिखाता है जहां वास्तव में अपवाद फेंक दिया गया है .. यह एम 2 -> एम 2 है। रेखा संख्या के साथ

दूसरा .. फेंक पूर्व द्वारा समझते हैं। एम 2 विधि पकड़ ब्लॉक में फेंक पूर्व के साथ फेंक दें। नीचे के अनुसार।

फेंक पूर्व कोड का उत्पादन नीचे जैसा है ..

आप आउटपुट में अंतर देख सकते हैं .. पूर्व को फेंक दें बस पिछले सभी पदानुक्रमों को अनदेखा करता है और लाइन / विधि के साथ स्टैक ट्रेस रीसेट करता है जहां पूर्व लिखा जाता है।


जब आप पूर्व फेंकते हैं, तो उस अपवाद को "मूल" बन जाता है। तो सभी पिछले स्टैक ट्रेस वहां नहीं होंगे।

यदि आप फेंकते हैं, तो अपवाद सिर्फ रेखा से नीचे चला जाता है और आपको पूर्ण स्टैक ट्रेस मिल जाएगा।


यहां देखें: http://blog-mstechnology.blogspot.de/2010/06/throw-vs-throw-ex.html

फेंको :

   try{
        // do some operation that can fail
   }
   catch (Exception ex)
   {
        // do some local cleanup
        throw;
   }

यह अपवाद के साथ स्टैक जानकारी को संरक्षित करता है

इसे "रेथ्रो" कहा जाता है

अगर नया अपवाद फेंकना चाहते हैं,

throw new ApplicationException("operation failed!");

थ्रो एक्स :

try
   {
        // do some operation that can fail
   }
   catch (Exception ex)
   {
        // do some local cleanup
        throw ex;
   }

यह अपवाद के साथ स्टैक जानकारी नहीं भेजेगा

इसे "ब्रेकिंग द स्टैक" कहा जाता है

अगर नया अपवाद फेंकना चाहते हैं,

throw new ApplicationException("operation failed!",ex);

हां, वहां एक अंतर है;

  • throw ex स्टैक ट्रेस को रीसेट करता है (इसलिए आपकी त्रुटियां HandleException से उत्पन्न होती हैं)
  • throw नहीं है - मूल अपराधी संरक्षित किया जाएगा।

int a = 0;
        try
        {
            int x = 4;
            int y ;
            try
            {
                y = x / a;
            }


            catch (Exception e)
            {
                Console.WriteLine("inner ex");
                //throw;   // Line 1
                //throw e;   // Line 2
                //throw new Exception("devide by 0");  // Line 3
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            throw ex;
        }
  1. यदि सभी लाइन 1, 2 और 3 टिप्पणी की जाती है - आउटपुट - आंतरिक पूर्व

  2. यदि सभी लाइन 2 और 3 पर टिप्पणी की जाती है - आउटपुट - आंतरिक पूर्व सिस्टम। डेविड बायज़ेरो अपवाद: {"शून्य से विभाजित करने का प्रयास किया गया।"} ---------

  3. यदि सभी पंक्ति 1 और 2 टिप्पणी की जाती है - आउटपुट - आंतरिक पूर्व प्रणाली। अपवाद: 0 से भरोसा ----

  4. यदि सभी लाइन 1 और 3 पर टिप्पणी की जाती है - आउटपुट - आंतरिक पूर्व सिस्टम। डेविड बायज़ेरो अपवाद: {"शून्य से विभाजित करने का प्रयास किया गया।"} --------- और स्टैकट्रेस को फेंकने के मामले में रीसेट किया जाएगा;







exception-handling