20

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

मैं इस पद्धति का उपयोग किया गया था rethrow लिए लेकिन यह स्टैक ट्रेस को साफ करता है:

try 
{ 
     return myDelegate.DynamicInvoke(args); 
} 
catch(TargetInvocationException ex) 
{ 
    Func<TargetInvocationException, Exception> getInner = null; 
    getInner = 
     delegate(TargetInvocationException e) 
     { 
     if (e.InnerException is TargetInvocationException) 
      return getInner((TargetInvocationException) e.InnerException); 

     return e.InnerException; 
     }; 

    Exception inner = getInner(ex); 
    inner.PreserveStackTrace(); 
    throw inner; 
} 

PreserveStackTrace विधि एक विस्तार विधि मैं एक और पोस्ट करने के लिए धन्यवाद तय है (मैं नहीं जानता कि यह वास्तव में क्या करता है) । बहरहाल, यह पता लगाने या तो संरक्षित करने के लिए प्रकट नहीं होता है:

public static void PreserveStackTrace(this Exception e) 
{ 
    var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain); 
    var mgr = new ObjectManager(null, ctx); 
    var si = new SerializationInfo(e.GetType(), new FormatterConverter()); 

    e.GetObjectData(si, ctx); 
    mgr.RegisterObject(e, 1, si); 
    mgr.DoFixups(); 
} 

उत्तर

27

तुम सिर्फ अपने स्टैक ट्रेस संरक्षण एक आंतरिक अपवाद फिर से फेंक करना चाहते हैं, तो आप इस तरह एक विधि के साथ यह कर सकते हैं:

public static void Rethrow(this Exception ex) 
{ 
    typeof(Exception).GetMethod("PrepForRemoting", 
     BindingFlags.NonPublic | BindingFlags.Instance) 
     .Invoke(ex, new object[0]); 
    throw ex; 
} 

इस तकनीक आरएक्स द्वारा किया जाता है (और के रूप में उनके द्वारा सामने आ रहा है एक विस्तार विधि Exception.PrepareForRethrow) और एसिंक सीटीपी द्वारा स्वचालित रूप से अनचाहे सिस्टम (सार्वजनिक रूप से उजागर एपीआई के बिना) द्वारा भी इसका उपयोग किया जाता है।

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

अद्यतन: एक आधिकारिक एपीआई .NET 4.5: ExceptionDispatchInfo में जोड़ा गया है।

+0

ध्यान देने योग्य दिलचस्प बिंदु: 4 में ExceptionDispatchInfo।5 का मतलब है कि आप आरएक्स से अलग-अलग कॉल स्टैक देखते हैं जब यह 4.0 या 4.5 को लक्षित कर रहे हैं या नहीं, इस पर निर्भर करता है कि यह अपवादों को पुनर्स्थापित कर रहा है। 4.5 को लक्षित करते समय अनचाहे ऑनरर्स को मूल स्टैक ट्रेस के साथ पुनर्स्थापित किया जाएगा, लेकिन 4.0 नहीं। –

0

IIRC यह पूरी तरह से अपवाद बनाए रखने के लिए, तथापि स्टैक ट्रेस कुछ प्रतिबिंब के साथ संरक्षित किया जा सकता संभव नहीं है। यहां ब्लॉग पोस्ट यह वर्णन करने का वर्णन करता है कि यह कैसे करें: http://iridescence.no/post/Preserving-Stack-Traces-When-Re-Throwing-Inner-Exceptions.aspx

2

आपको यह ध्यान रखना होगा कि क्यों .NET केवल मूल अपवाद को देने के बजाय TargetInvocationException के साथ अपवाद को लपेटता है। इसके लिए वास्तव में एक अच्छा कारण है, यह स्पष्ट नहीं है कि अपवाद के वास्तविक कारण से आया था। ऐसा इसलिए था क्योंकि डायनामिक इनवोक() कॉल बोर्क किया गया है? असंभव नहीं है, ऐसा कुछ भी नहीं है कि संकलक यह सुनिश्चित करने के लिए कर सके कि सही तर्क पारित किए गए हैं। या क्या चालित लक्ष्य विधि स्वयं ही फेंक देती है?

अपवाद के वास्तविक कारण का न्याय करने के लिए आपको दोनों जानने की आवश्यकता है। जानबूझकर लक्ष्यInvocationException को छिपाने से आपको हार्ड समस्या का स्रोत निदान करने के लिए समय दिया जा रहा है यदि यह वास्तव में डायनामिक इनवोक() कॉल में कोई समस्या थी। ऐसा करने से बचें।

+1

मैं तर्क की सराहना करता हूं लेकिन यह उपभोग करने वाले कोड को लिखना अधिक कठिन बनाता है क्योंकि विशिष्ट त्रुटियों को स्पष्ट रूप से पकड़ने की लचीलापन समाप्त हो जाती है। –

+1

इस परिदृश्य में अपवादों को पकड़ना वैसे भी असाधारण मुश्किल है। आप प्रतिनिधि लक्ष्य के बारे में कुछ नहीं जानते हैं, आप अनुमान लगा सकते हैं कि इसने कार्यक्रम की स्थिति को कैसे बदल दिया। और जब आप अपवाद को संभालने के दौरान स्थिति को पुनर्स्थापित नहीं कर सकते हैं। –

+0

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

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