2012-09-11 13 views
10
में करता है

संभव डुप्लिकेट:
incorrect stacktrace by rethrowफेंक; स्टैक ट्रेस रीसेट नहीं करने के लिए कहा जाता है, लेकिन यह कुछ निश्चित परिस्थितियों

यह आम तौर पर स्वीकार किया जाता है कि .NET में throw; स्टैक ट्रेस रीसेट नहीं करता, लेकिन throw ex; करता है।

void Main() 
{ 
    try 
    { 
     try 
     { 
      Wrapper(); // line 13 
     } 
     catch(Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
      throw; // line 18 
     } 
    } 
    catch(Exception e) 
    { 
      Console.WriteLine(e.ToString()); 
    } 
} 

public void Wrapper() 
{ 
    Throw(); // line 28 
} 

public void Throw() 
{ 
    var x = (string)(object)1; // line 33 
} 

उत्पादन होता है:

System.InvalidCastException: करने के लिए प्रकार की वस्तु 'System.Int32' कास्ट करने में असमर्थ

हालांकि, इस साधारण प्रोग्राम में, मैं अलग लाइन नंबर मिल 'System.String' टाइप करें। ConsoleApplication2.Program.Main पर (String [] args) C: \ लंबी पथ \ Program.cs: लाइन 13

System.InvalidCastException: प्रकार की वस्तु कास्ट करने के लिए 'System.Int32' टाइप करने में असमर्थ 'सिस्टम .String '। ConsoleApplication2.Program.Main पर (String [] args) C: \ लंबी पथ \ Program.cs: लाइन 18

नोट: पहले स्टैक ट्रेस लाइन 13 होता है, दूसरा इसके अतिरिक्त लाइन 18. शामिल , न तो लाइन 13 और न ही लाइन 18 लाइनें हैं जहां कास्ट वास्तव में हो रहा है।

मेरा प्रश्न अब है: किस परिस्थितियों में throw; स्टैक ट्रेस बदलता है और किस परिस्थिति में यह स्टैक ट्रेस बदलता नहीं है?

कृपया ध्यान दें, कि यह पहले से ही been observed है, लेकिन सामान्य रूप से उत्तर नहीं दिया गया है।


अद्यतन:
मैं डीबग मोड में उपरोक्त कोड भाग गया और यह इस पैदावार:

System.InvalidCastException: प्रकार की वस्तु कास्ट करने के लिए 'System.Int32' टाइप करने के लिए 'में असमर्थ System.String '। कंसोल अनुप्रयोग में कंसोल एप्लाइंस 2.प्रोग्राम। थ्रो() में सी: \ लांग-पथ \ प्रोग्राम सीएस: लाइन 33 कंसोल एप्प्लिकेशन 2.प्रोग्राम। रैपर() में सी: \ लांग-पथ \ प्रोग्राम.cs: लाइन 28 कंसोल अनुप्रयोग 2 पर। कार्यक्रम। मुख्य (स्ट्रिंग [] args) सी: \ long-path \ program.cs: लाइन 13

सिस्टम। इन्वालिड कैस्ट अपवाद: 'System.String' टाइप करने के लिए 'System.Int32' प्रकार की ऑब्जेक्ट डालने में असमर्थ। कंसोल अनुप्रयोग में कंसोल एप्लाइंस 2.प्रोग्राम। थ्रो() में सी: \ लांग-पथ \ प्रोग्राम सीएस: लाइन 33 कंसोल एप्प्लिकेशन 2.प्रोग्राम। रैपर() में सी: \ लांग-पथ \ प्रोग्राम.cs: लाइन 28 कंसोल अनुप्रयोग 2 पर। Program.Main सी में (String [] args): \ लंबी पथ \ Program.cs: लाइन 18

कृपया ध्यान दें: अंतिम पंक्ति संख्या अब भी कोई परिवर्तन

+0

यह आपके द्वारा प्रदान किए गए कोड के स्निपेट से संबंधित अपवादों में विस्तृत लाइन संख्याओं की विस्तृत सहायता करेगा ... –

+0

@ पीटररची: हो गया। –

उत्तर

4

डैरिन पहले से ही बाहर बिंदु के रूप में कम स्टैक ट्रेस विधि इनलाइनिंग के कारण है। हालांकि स्टैक ट्रेस में उपलब्ध लाइन संदर्भ का बिंदु भी बराबर नहीं है।

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

मैं इस बारे में बात की और निम्न ब्लॉग पोस्ट में अपवाद rethrow करने के विभिन्न तरीकों पर पूर्ण उदाहरण प्रस्तुत:

.NET Exceptions – throw ex is evil but throw is not that innocent


आपकी टिप्पणी मुझे एक त्वरित अनुसंधान के लिए प्रेरित किया, लेकिन सबसे अच्छा मैं मिल सकता है catch and rethrow के बारे में ब्लॉग पोस्ट पर जोनाथन डी हैलेक्स द्वारा यह टिप्पणी थी:

यह टी में स्टैकट्रैक में लाइन नंबर भी बदलता है वह विधि है कि rethrows (चूंकि रीथ्रो उस विधि में फेंकने की साइट बन जाता है)।

यह आगे सविस्तार किया जा सकता है, लेकिन यह सच है कि शायद फेंक साइट जो तब लाइन जानकारी प्राप्त करने के लिए इस्तेमाल किया जाएगा प्रत्येक विधि पर की जाती है और rethrow का कारण बनता है यह ओवरराइड करने के लिए के लिए अंक।

तो भले ही स्टैकट्रेस का उपयोग करते समय throwthrow e के बजाय मूल फेंक साइट जब तक आप लपेट और कोई नया अपवाद फेंक खो जाएगा संरक्षित है।

अन्य चीजों को आजमाएं; चूंकि एसओ सीधे संदेशों की अनुमति नहीं देता है और उपर्युक्त टिप्पणी Peli द्वारा बनाई गई थी, आप अपना प्रश्न प्राप्त करने के लिए pex के साथ इस प्रश्न को टैग करने का प्रयास कर सकते हैं और उसे उस टिप्पणी पर अनुवर्ती करने के लिए प्राप्त कर सकते हैं। :)

+1

धन्यवाद। मुझे पता है कि लपेटने से यह पूरे स्टैक ट्रेस को सुरक्षित रखेगा। मैंने इस प्रश्न से भविष्य के पदों के लिए एक संदर्भ देने के लिए कहा जहां लोग केवल 'फेंक' का उपयोग करते हैं, क्योंकि यह स्टैक ट्रेस को संरक्षित करता है "वास्तव में यह हमेशा ऐसा नहीं करता है। –

+0

मैंने आगे की जानकारी के साथ सवाल को इंटरवेब्स के रूप में अपडेट किया है, जिसे आप पहले ही देख सकते हैं, लेकिन संदर्भ के लिए उपयोगी हो सकता है। हालांकि, यह अभी भी पूरी तरह से विषय की व्याख्या नहीं करता है। –

5

हो रहा के लिए कारण की वजह से है रिलीज मोड में चलते समय विधि को रेखांकित करना।आप Wrapper और Throw तरीकों रिलीज मोड में inlined जा करने के लिए नहीं करना चाहते हैं तो आप उन्हें [MethodImpl] विशेषता के साथ सजाने कर सकते हैं:

[MethodImpl(MethodImplOptions.NoInlining)] 
public void Wrapper() 
{ 
    Throw(); 
} 

[MethodImpl(MethodImplOptions.NoInlining)] 
public void Throw() 
{ 
    var x = (string)(object)1; 
} 
+1

ठीक है, यह बताता है कि पहली पकड़ में रेखा संख्या कास्ट की रेखा संख्या क्यों नहीं है। यह अभी भी व्याख्या नहीं करता है कि क्यों 'फेंक'; स्टैक ट्रेस में लाइन नंबर बदलता है। –

+0

मैं उन पंक्तियों के साथ कुछ कहने वाला था, इसलिए बस जोड़ने के लिए: डीबग मोड में कोड चलाने से पूर्ण कॉल स्टैक उत्पन्न होते हैं जो दोनों 'थ्रो' विधि में उत्पन्न होते हैं। –

+0

@DanielHilgarth आप जिस लाइन नंबर को देख रहे हैं वह वह रेखा है जहां अपवाद को फिर से फेंक दिया गया था। एक रिलीज बिल्ड में यह सब कुछ मिलता है जैसे बाकी को रेखांकित किया गया है। यदि आप अपवाद की उत्पत्ति चाहते हैं, तो आपको पूर्ण ढेर की आवश्यकता है। –

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