2010-03-22 23 views
27

मैं इस कोड हैगलत लाइन नंबर

try 
{ 
    //AN EXCEPTION IS GENERATED HERE!!! 
} 
catch 
{ 
    SqlService.RollbackTransaction(); 
    throw; 
} 

कोड के ऊपर यह कोड

try 
{ 
    //HERE IS CALLED THE METHOD THAT CONTAINS THE CODE ABOVE 
} 
catch (Exception ex) 
{ 
    HandleException(ex); 
} 
में कहा जाता है

अपवाद विधि "HandleException" करने के लिए पैरामीटर के रूप में पारित कर दिया की लाइन नंबर शामिल वास्तविक रेखा के बजाय स्टैक ट्रेस में "फेंक" रेखा जहां अपवाद उत्पन्न हुआ था। कोई जानता है कि यह क्यों हो रहा है?

EDIT1 ठीक है, आपके उत्तरों के लिए धन्यवाद। मैं के लिए


catch(Exception ex) 
{ 
    SqlService.RollbackTransaction(); 
    throw new Exception("Enrollment error", ex); 
} 

अब मैं स्टैक ट्रेस पर सही लाइन भीतरी पकड़ बदल गया है, लेकिन मैं एक नया अपवाद बनाने के लिए किया था। मैं :-(

EDIT2 हो सकता है कि एक बेहतर समाधान (आप 5 मिनट है तो) आप अगर आप एक ही परिणाम है, बहुत से बनाना जटिल नहीं मिल की जांच करने के क्रम में इस परिदृश्य की कोशिश कर सकते लगता है की उम्मीद कर रहा था।

+5

क्या आप सुनिश्चित हैं कि यह 'थ्रो एक्स' नहीं कहता है? – SLaks

+0

100% निश्चित, अजीब: -s –

+2

क्या मूल अपवाद एक से छुपाया जा सकता है शायद SqlService.RollbackTransaction द्वारा फेंक दिया जा रहा है? –

उत्तर

34

हां, यह अपवाद हैंडलिंग तर्क में एक सीमा है। यदि किसी विधि में एक से अधिक फेंक स्टेटमेंट होता है जो अपवाद फेंकता है तो आपको अंतिम आखिरी पंक्ति की रेखा संख्या मिल जाएगी। इस उदाहरण कोड इस व्यवहार reproduces:

using System; 

class Program { 
    static void Main(string[] args) { 
     try { 
      Test(); 
     } 
     catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
     } 
     Console.ReadLine(); 
    } 
    static void Test() { 
     try { 
      throw new Exception(); // Line 15 
     } 
     catch { 
      throw;     // Line 18 
     } 
    } 
} 

आउटपुट:

System.Exception: Exception of type 'System.Exception' was thrown. 
    at Program.Test() in ConsoleApplication1\Program.cs:line 18 
    at Program.Main(String[] args) in ConsoleApplication1\Program.cs:line 6 

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

इस तरह

:

static void Test() { 
    try { 
     Test2();    // Line 15 
    } 
    catch { 
     throw;     // Line 18 
    } 
} 
static void Test2() { 
    throw new Exception();  // Line 22 
} 

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

+0

धन्यवाद! सुनिश्चित नहीं है कि आप हेल्पे द्वारा क्या मतलब रखते हैं आर विधि। मेरे कोड और आपके कोड पर अपवाद एक अलग विधि पर उत्पन्न होता है। –

+1

@ क्लाउडियो: मैंने यह दिखाने के लिए पोस्ट अपडेट किया कि सहायक विधि कैसा दिखता है। –

4

सी # स्टैक ट्रेस फेंक समय में उत्पन्न कर रहे हैं, अपवाद निर्माण समय पर नहीं।

यह जावा, जहां स्टैक ट्रेस अपवाद निर्माण समय में भर रहे हैं से अलग है।

इस डिजाइन से जाहिरा तौर पर है।

+1

हां, लेकिन 'फेंक;' मूल स्टैक ट्रेस को संरक्षित करता है। – SLaks

+0

@ स्लक्स: उत्कृष्ट बिंदु। एंडी शेलम की मूल प्रश्न पर टिप्पणी के आधार पर, मुझे लगता है कि शायद मूल अपवाद पकड़ ब्लॉक में अपवाद द्वारा निगल लिया जा रहा है। – Randolpho

5

क्या आपकी .pdb फ़ाइल की दिनांक/समय टिकट आपकी .exe/.dll फ़ाइल से मेल खाता है? यदि नहीं, तो यह हो सकता है कि संकलन "डीबग मोड" में नहीं है जो प्रत्येक बिल्ड पर एक ताजा .pdb फ़ाइल उत्पन्न करता है। अपवाद होने पर पीडीबी फ़ाइल में सटीक रेखा संख्या होती है।

डीबग डेटा उत्पन्न होने के लिए सुनिश्चित करने के लिए अपनी संकलन सेटिंग्स देखें, या यदि आप परीक्षण/उत्पादन वातावरण में हैं, तो टाइमस्टैम्प मैच सुनिश्चित करने के लिए .pdb फ़ाइल देखें।

+0

दिलचस्प संभव साइड- उत्तर। +1 – Randolpho

+0

एक से अधिक अवसरों पर मेरे साथ हुआ है। 8^डी –

+0

तिथियां मैच, बस दो बार चेक किया गया –

10

"लेकिन फेंक; स्टैक ट्रेस को बरकरार रखता है !! फेंक का प्रयोग करें,"

आप कितनी बार सुना है कि ... खैर जो भी के लिए नेट प्रोग्रामिंग कर दिया गया है जबकि लगभग निश्चित रूप से सुना है और संभवतः इसे सभी के रूप में स्वीकार कर लिया है और सभी 'पुनर्विचार' अपवादों को समाप्त कर दिया है।

दुर्भाग्यवश यह हमेशा सत्य नहीं होता है। जैसा कि @ हंस बताते हैं, अगर अपवाद का कारण कोड throw; कथन के समान तरीके से होता है तो स्टैक ट्रेस उस रेखा पर रीसेट हो जाता है।

एक समाधान try, catch के अंदर कोड को एक अलग विधि में निकालने का है, और दूसरा समाधान एक अपवाद के रूप में पकड़े गए अपवाद के साथ एक नया अपवाद फेंकना है। एक नई विधि थोड़ा बेकार है, और new Exception() मूल अपवाद प्रकार खो देता है यदि आप इसे कॉल स्टैक को आगे पकड़ने का प्रयास करते हैं।

मुझे इस समस्या का बेहतर विवरण मिला Fabrice Marguerie's blog पर मिला।

लेकिन और भी बेहतर कोई और StackOverflow सवाल जो समाधान है (भले ही उनमें से कुछ प्रतिबिंब शामिल) है:

  In C#, how can I rethrow InnerException without losing stack trace?

+0

+1 साइमन आपके उत्तर के लिए धन्यवाद :) मैं उन लिंक की जांच करूँगा –

3

मैं अक्सर उत्पादन प्रणालियों में इस मिल अगर Optimize code चेक किया गया है। यह 2016 में भी लाइन संख्याओं को खराब करता है।

सुनिश्चित करें कि आपकी कॉन्फ़िगरेशन 'रिलीज़' पर सेट है या जो भी कॉन्फ़िगरेशन आप बना रहे हैं और तैनात कर रहे हैं। चेकबॉक्स में प्रति कॉन्फ़िगरेशन

मुझे कभी अंततः पता नहीं है कि मेरे कोड को इस चेक के साथ 'अनुकूलित' किया गया है - इसलिए यदि आपको आवश्यकता हो तो इसे वापस जांचें - लेकिन इसने कई मौकों पर अपना स्टैक ट्रेस सहेजा है।

enter image description here

2

.NET फ्रेमवर्क 4.5 के रूप में आप किसी अन्य विधि की आवश्यकता के बिना यह करने के लिए ExceptionDispatchInfo वर्ग का उपयोग कर सकते हैं। उदाहरण के लिए, हंस 'उत्कृष्ट जवाब है, से कोड उधार तुम सिर्फ throw उपयोग करते हैं, इस तरह:

using System; 

class Program { 
    static void Main(string[] args) { 
     try { 
      Test(); 
     } 
     catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
     } 
     Console.ReadLine(); 
    } 
    static void Test() { 
     try { 
      throw new ArgumentException(); // Line 15 
     } 
     catch { 
      throw;       // Line 18 
     } 
    } 
} 

यह इस आउटपुट:

System.ArgumentException: Value does not fall within the expected range. 
    at Program.Test() in Program.cs:line 18 
    at Program.Main(String[] args) in Program.cs:line 6 

लेकिन, आप ExceptionDispatchInfo उपयोग कर सकते हैं पर कब्जा और फिर से इस तरह, अपवाद:

using System; 

class Program { 
    static void Main(string[] args) { 
     try { 
      Test(); 
     } 
     catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
     } 
     Console.ReadLine(); 
    } 
    static void Test() { 
     try { 
      throw new ArgumentException();    // Line 15 
     } 
     catch(Exception ex) { 
      ExceptionDispatchInfo.Capture(ex).Throw(); // Line 18 
     } 
    } 
} 

तो यह होगा उत्पादन इस:

System.ArgumentException: Value does not fall within the expected range. 
    at Program.Test() in Program.cs:line 15 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at Program.Test() in Program.cs:line 18 
    at Program.Main(String[] args) in Program.cs:line 6 

आप देख सकते हैं, ExceptionDispatchInfo.Throw मूल अपवाद के स्टैक ट्रेस करने के लिए अतिरिक्त जानकारी जोड़ देती है, तथ्य यह है कि इसे फिर से फेंक दिया गया था जोड़ने, लेकिन यह मूल लाइन नंबर और अपवाद प्रकार बरकरार रखती है। अधिक जानकारी के लिए MSDN documentation देखें।

संबंधित मुद्दे