नए अपवाद को फेंकने और फेंकने के बीच अंतर ()


164

दोनों के बीच क्या अंतर है

try { ... }
catch{ throw } 

तथा

try{ ... }
catch(Exception e) {throw new Exception(e.message) } 

बावजूद इसके कि दूसरा संदेश दिखाता है?


51
दूसरा स्निपेट कोड की सबसे बुरी (लेकिन अहानिकर) लाइनों में से एक है जिसे मैंने कभी देखा है।
SLACs

जवाबों:


259

throw; मूल अपवाद को पुनर्व्यवस्थित करता है और इसके मूल स्टैक ट्रेस को संरक्षित करता है।

throw ex; मूल अपवाद को फेंकता है लेकिन स्टैक ट्रेस को रीसेट करता है, तब तक सभी स्टैक ट्रेस जानकारी को नष्ट कर देता है catch ब्लॉक ।


कभी नहीँ लिखतेthrow ex;


throw new Exception(ex.Message);और भी बुरा है। यह एक नया Exceptionउदाहरण बनाता है , अपवाद के मूल स्टैक को खोने के साथ-साथ इसके प्रकार को भी। (जैसे, IOException)।
इसके अलावा, कुछ अपवाद अतिरिक्त जानकारी रखते हैं (जैसे,ArgumentException.ParamName ) रखते हैं।
throw new Exception(ex.Message); इस जानकारी को भी नष्ट कर देगा।

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

ऐसा करने के लिए, एक नया वर्ग परिभाषित करें जो विरासत में मिला है Exception, सभी चार अपवाद निर्माणकर्ताओं को जोड़ें , और वैकल्पिक रूप से एक अतिरिक्त निर्माणकर्ता जो एक InnerExceptionअतिरिक्त जानकारी लेता है , और पैरामीटर के रूप में गुजरते हुएexInnerException अपने नए अपवाद वर्ग को फेंक दें । मूल पास करके InnerException, आप स्टैक ट्रेस सहित मूल अपवाद के सभी गुणों को संरक्षित करते हैं।


24
"नया अपवाद (एक्स) फेंक दो; और भी बुरा है।": मैं इस पर असहमत हूं। कभी-कभी आप एक अपवाद के प्रकार को बदलना चाहते हैं, और फिर मूल अपवाद को आंतरिक अपवाद के रूप में रखना सबसे अच्छा है जो आप कर सकते हैं। हालांकि यह throw new MyCustomException(myMessage, ex);जरूर होना चाहिए ।
डर्क वोल्मार

9
@ 0xA3: मैं मतलब ex.Messageहै, जो है भी बदतर।
SLACs

6
मानक निर्माणकर्ताओं को लागू करने के अलावा, किसी को कस्टम अपवाद भी बनाना चाहिए [Serializable()]
डिर्क वोल्मार

21
यो डॉग, हम आपको अपवाद पसंद करते हैं, इसलिए हम यो के अपवाद में एक अपवाद रखते हैं ताकि आप पकड़ते समय पकड़ सकें।
डार्थ कॉन्टिनेंट

2
@SLaks: जब आप throw;वास्तविक लाइन नंबर, जहां अपवाद होता है, की लाइन संख्या द्वारा प्रतिस्थापित किया जाता है throw;। आप इसे कैसे हैंडल करने का सुझाव देते हैं? stackoverflow.com/questions/2493779/…
एरिक जे।

34

पहला मूल स्टैकट्रेस संरक्षित करता है:

try { ... }
catch
{
    // Do something.
    throw;
}

दूसरा आपको अपवाद और / या संदेश और अन्य डेटा के प्रकार को बदलने की अनुमति देता है:

try { ... } catch (Exception e)
{
    throw new BarException("Something broke!");
}

एक तीसरा तरीका भी है जहाँ आप एक आंतरिक अपवाद को पार करते हैं:

try { ... }
catch (FooException e) {
    throw new BarException("foo", e);
} 

मैं उपयोग करने की सलाह दूंगा:

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

6

एक अन्य बिंदु जो मैंने किसी को बनाते नहीं देखा:

यदि आप अपने कैच {} ब्लॉक में कुछ नहीं करते हैं, तो एक कोशिश करें ... कैच व्यर्थ है। मैं इसे हमेशा देखता हूं:

try 
{
  //Code here
}
catch
{
    throw;
}

या खराब:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw ex;
}

अभी तक सबसे खराब:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw new System.Exception(ex.Message);
}

मैं सहमत हूं, जब तक कि आपके पास अंत में खंड न हो।
टोनी रोसमन

1
@ToniRossmann इस मामले में मैं कोशिश करूँगा..बिना पकड़ के, जब तक आप फेंक के अलावा कुछ नहीं कर रहे हों;
JLWarlow

4

throw स्टैक ट्रेस को बनाए रखते हुए पकड़े गए अपवाद को फिर से फेंकता है throw new Exception कुछ विवरण खो देता है।

आप सामान्य रूप से उपयोग करेंगे throw से उस बिंदु पर पूरी तरह से निपटने के बिना एक अपवाद को लॉग करने के लिए स्वयं द्वारा ।

BlackWasp का एक अच्छा लेख है, जिसका शीर्षक C # में थ्रोइंग एक्सेप्शन है


4

एक नया अपवाद फेंकने से वर्तमान स्टैक ट्रेस दूर हो जाता है।

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

catch(Exception e)
{
    throw new CustomException(customMessage, e);
}

3

throwएक पकड़े गए अपवाद को फिर से उखाड़ फेंकने के लिए है। यह उपयोगी हो सकता है यदि आप कॉल श्रृंखला को पारित करने से पहले अपवाद के साथ कुछ करना चाहते हैं।

throwबिना किसी तर्क के उपयोग करना डिबगिंग उद्देश्यों के लिए कॉल स्टैक को संरक्षित करता है।


0

यदि आप चाहते हैं कि आप एक अपवाद के रूप में मूल अपवाद के साथ एक नया अपवाद फेंक सकते हैं।


0

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


हाँ, यह उन सवालों में से एक है जहाँ आपको तेजी से लिखना है। ;)
रॉबर्ट हार्वे

0

सबसे महत्वपूर्ण अंतर यह है कि दूसरी अभिव्यक्ति अपवाद के प्रकार को मिटा देती है। और अपवाद प्रकार अपवादों को पकड़ने में महत्वपूर्ण भूमिका निभाता है:

public void MyMethod ()
{
    // both can throw IOException
    try { foo(); } catch { throw; }
    try { bar(); } catch(E) {throw new Exception(E.message); }
}

(...)

try {
    MyMethod ();
} catch (IOException ex) {
    Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
    Console.WriteLine ("Other error");    // [2]
}

यदि foo()फेंकता है IOException, तो [1]पकड़ ब्लॉक अपवाद को पकड़ लेगा। लेकिन जब bar()फेंकता है IOException, तो इसे सादे Exceptionचींटी में बदल दिया जाएगा जो कि [1]कैच ब्लॉक से नहीं पकड़ा जाएगा ।


0

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


0

फेंकना; मूल अपवाद को रीथ्रो करें और अपवाद प्रकार रखें।

नया अपवाद फेंकें (); मूल अपवाद प्रकार को रीथ्रो करें और अपवाद स्टैक ट्रेस को रीसेट करें

पूर्व फेंक; अपवाद स्टैक ट्रेस रीसेट करें और अपवाद प्रकार रीसेट करें


-1

यहां कोई भी उत्तर अंतर नहीं दिखाता है, जो अंतर को समझने के लिए संघर्ष कर रहे लोगों के लिए मददगार हो सकता है। इस नमूना कोड पर विचार करें:

using System;
using System.Collections.Generic;

namespace ExceptionDemo
{
   class Program
   {
      static void Main(string[] args)
      {
         void fail()
         {
            (null as string).Trim();
         }

         void bareThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw;
            }
         }

         void rethrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw e;
            }
         }

         void innerThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw new Exception("outer", e);
            }
         }

         var cases = new Dictionary<string, Action>()
         {
            { "Bare Throw:", bareThrow },
            { "Rethrow", rethrow },
            { "Inner Throw", innerThrow }
         };

         foreach (var c in cases)
         {
            Console.WriteLine(c.Key);
            Console.WriteLine(new string('-', 40));
            try
            {
               c.Value();
            } catch (Exception e)
            {
               Console.WriteLine(e.ToString());
            }
         }
      }
   }
}

जो निम्न आउटपुट उत्पन्न करता है:

Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
   at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
   at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
   --- End of inner exception stack trace ---
   at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

नंगे थ्रो, जैसा कि पिछले उत्तरों में दर्शाया गया है, स्पष्ट रूप से कोड की मूल पंक्ति (पंक्ति 12) के साथ-साथ अपवाद (19 और 64) होने पर कॉल स्टैक में सक्रिय दो अन्य बिंदुओं को दिखाता है।

री-थ्रो केस का आउटपुट दिखाता है कि यह समस्या क्यों है। जब अपवाद को इस तरह से हटा दिया जाता है तो अपवाद में मूल स्टैक जानकारी शामिल नहीं होगी। ध्यान दें कि केवल throw e(लाइन 35) और सबसे बाहरी कॉल स्टैक बिंदु (लाइन 64) शामिल हैं। यदि आप इस तरह से अपवाद फेंकते हैं तो समस्या के स्रोत के रूप में असफल () पद्धति को ट्रैक करना मुश्किल होगा।

अंतिम मामला (इनरथ्रो) सबसे विस्तृत है और इसमें उपरोक्त दोनों में से अधिक जानकारी शामिल है। चूंकि हम एक नए अपवाद को तात्कालिक कर रहे हैं, इसलिए हमें प्रासंगिक जानकारी ("बाहरी" संदेश, यहाँ जोड़ने का मौका मिलता है, लेकिन हम नए अपवाद में .Data शब्दकोश में जोड़ सकते हैं) और साथ ही मूल में सभी जानकारी को संरक्षित कर सकते हैं। अपवाद (सहायता लिंक, डेटा शब्दकोश, आदि सहित)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.