थोड़ी देर के लूप का उपयोग किए बिना आंतरिक-सबसे अपवाद का पता लगाएं?


84

जब C # एक अपवाद फेंकता है, तो इसका एक आंतरिक अपवाद हो सकता है। मैं जो करना चाहता हूं उसे आंतरिक-सबसे अधिक अपवाद मिलता है, या दूसरे शब्दों में, पत्ती अपवाद जिसमें आंतरिक अपवाद नहीं है। मैं थोड़ी देर में यह कर सकता हूं:

while (e.InnerException != null)
{
    e = e.InnerException;
}

लेकिन मैं सोच रहा था कि क्या कोई एक-लाइनर था जिसका उपयोग मैं इसके बजाय कर सकता था।


4
मैं अपनी एक कक्षा में एक अपवाद फेंक रहा हूं, लेकिन मेरी कक्षा का उपयोग एक पुस्तकालय द्वारा किया जा रहा है जो सभी अपवादों को निगलता है और अपना स्वयं का फेंकता है। समस्या यह है कि, पुस्तकालय अपवाद बहुत सामान्य है और मुझे यह जानने की आवश्यकता है कि समस्या को कैसे संभालना है, यह जानने के लिए मैंने कौन से विशिष्ट अपवाद को फेंक दिया। चीजों को बदतर बनाने के लिए, पुस्तकालय अपने स्वयं के अपवाद को कई बार एक दूसरे में घोंसले में फेंक देगा, एक मनमाना गहराई तक। उदाहरण के लिए, यह फेंक देगा LibraryException -> LibraryException -> LibraryException -> MyException। मेरा अपवाद हमेशा श्रृंखला पर अंतिम होता है और इसका अपना आंतरिक अपवाद नहीं होता है।
डेनियल टी।

ओह, मुझे लगता है कि आप अपने आप को अंतरतम तक ले जा सकते हैं, इसलिए खुद (और वेरिएंट जैसे अंतरतम जो एक विशेष प्रकार से प्राप्त होता है) कर रहे हैं, लेकिन मुझे यह नहीं मिलता कि आपके पास पहले से क्या समस्या है।
जॉन हन्ना

ओह, मैं समझता हूं कि तुम्हारा क्या मतलब है। मैं सोच रहा था कि क्या यह लिखने का एक और तरीका है। मैं LINQतो लगभग सब कुछ करने के लिए उपयोग करने के लिए इस्तेमाल किया है कि यह अजीब लगता है जब मैं एक पाश लिखना है। मैं ज्यादातर डेटा एक्सेस के साथ काम करता हूं इसलिए मैं ICollectionsलगभग हर चीज के लिए बहुत काम करता हूं।
डैनियल टी।

@ डैनियल, LINQबस इस तथ्य को मास्क नहीं कर रहा है कि कोड अभी भी अनिवार्य रूप से लूप है? क्या .NET में कोई सही सेट-आधारित कमांड हैं?
ब्रैड

6
सबसे सही उत्तर नीचे (केवल) 2 वोटों के साथ नीचे की ओर झुका हुआ है - Exception.GetBaseException ()। यह मूल रूप से हमेशा के लिए ढांचे में रहा है। शुचिता की जाँच के लिए बैटकैल्ट का धन्यवाद।
जय

जवाबों:


139

एक लाइन :)

while (e.InnerException != null) e = e.InnerException;

जाहिर है, आप इसे कोई सरल नहीं बना सकते।

जैसा कि ग्लेन मैक्लेहो द्वारा इस उत्तर में कहा गया है , यह एकमात्र विश्वसनीय तरीका है।


7
GetBaseException () विधि इस w / oa लूप को करती है। msdn.microsoft.com/en-us/library/…
codingoutloud

8
यह काम करता है जबकि Exception.GetBaseException()मेरे लिए नहीं था।
तारिक

122

मेरा मानना Exception.GetBaseException()है कि इन समाधानों के रूप में एक ही बात करता है।

कैविएट: विभिन्न टिप्पणियों से हमें पता चला है कि यह हमेशा एक ही काम नहीं करता है, और कुछ मामलों में पुनरावर्ती / पुनरावृत्ति समाधान आपको आगे मिलेगा। यह आमतौर पर अंतरतम अपवाद है, जो निराशाजनक रूप से असंगत है, कुछ प्रकार के अपवादों के लिए धन्यवाद जो डिफ़ॉल्ट को ओवरराइड करता है। हालाँकि यदि आप विशिष्ट प्रकार के अपवादों को पकड़ते हैं और यह सुनिश्चित करते हैं कि वे ऑडबॉल (जैसे एग्रीगेटएक्स अपवाद) नहीं हैं, तो मुझे उम्मीद है कि इसे वैध अंतरतम / जल्द से जल्द अपवाद मिलेगा।


3
+1 जटिल समाधानों से बचने के लिए बीसीएल को जानने जैसा कुछ नहीं है। स्पष्ट रूप से, यह सबसे सही उत्तर है।
जे

4
किसी कारण के लिए, GetBaseException()बहुत पहले रूट अपवाद को वापस नहीं किया।
तारिक

4
ग्लेन मैकलेहो ने बताया कि वास्तव में GetBaseException () हमेशा वह नहीं करता है जो MSDN बताता है कि हम सामान्य रूप से उम्मीद कर सकते हैं (कि "अपवाद जो एक या अधिक बाद के अपवादों का मूल कारण है")। AggregateException में यह एक ही प्रकार के सबसे कम अपवाद तक सीमित है, और शायद अन्य हैं।
जोश सटरफील्ड

1
मेरे मुद्दे के लिए काम नहीं करता है। मेरे पास इससे अधिक स्तर है जो यह प्रदान कर रहा है।
गियोवन्नी बी

2
GetBaseException()मेरे लिए काम नहीं किया, क्योंकि शीर्ष-सबसे अपवाद एक एग्रीग्रेट एक्ससेप्शन है।
क्रिस बैलेंस

22

इनर एक्सेप्शन के माध्यम से लूपिंग एकमात्र विश्वसनीय तरीका है।

यदि पकड़ा गया अपवाद एक AggregateException है, तो GetBaseException()केवल सबसे अलग AggregateException देता है।

http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx


1
अच्छी पकड़। धन्यवाद - जो ऊपर की टिप्पणियों की व्याख्या करता है, जहां कुछ लोगों के लिए यह जवाब काम नहीं कर रहा था। यह स्पष्ट करता है कि MSDN का सामान्य विवरण "एक या एक से अधिक बाद के अपवादों का मूल कारण" हमेशा ऐसा नहीं होता है जिसे आप मान लें क्योंकि व्युत्पन्न वर्ग इसे ओवरराइड कर सकते हैं। वास्तविक नियम यह प्रतीत होता है कि GetBaseException () पर अपवाद "श्रृंखला" में सभी अपवाद हैं और उसी वस्तु को वापस करते हैं, जो AggregateException के लिए मामला लगता है।
जोश सटरफील्ड

12

यदि आप नहीं जानते कि आंतरिक अपवाद कितने गहरे हैं, तो पाश या पुनरावृत्ति के आसपास कोई रास्ता नहीं है।

बेशक, आप एक विस्तार विधि को परिभाषित कर सकते हैं जो इसे दूर करती है:

public static class ExceptionExtensions
{
    public static Exception GetInnermostException(this Exception e)
    {
        if (e == null)
        {
            throw new ArgumentNullException("e");
        }

        while (e.InnerException != null)
        {
            e = e.InnerException;
        }

        return e;
    }
}

10

मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन मुझे आश्चर्य है कि किसी ने भी यह सुझाव नहीं दिया GetBaseException()कि यह Exceptionकक्षा में एक विधि है :

catch (Exception x)
{
    var baseException = x.GetBaseException();
}

यह .NET 1.1 के बाद से आसपास है। यहाँ प्रलेखन: http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx


5 दिसंबर 2012 से पहले संकेत दिया गया था
armadillo.mx

2

कभी-कभी आपके पास कई आंतरिक अपवाद हो सकते हैं (कई बुदबुदाने वाले अपवाद)। जिस स्थिति में आप करना चाहते हैं:

List<Exception> es = new List<Exception>();
while(e.InnerException != null)
{
   es.add(e.InnerException);
   e = e.InnerException
}


1

वास्तव में इतना आसान है, आप उपयोग कर सकते हैं Exception.GetBaseException()

Try
      //Your code
Catch ex As Exception
      MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
End Try

आपके समाधान के लिए धन्यवाद! कुछ लोग VB में सोचते हैं: D
फेडेरिको नवरेट

1
और वहाँ एक कारण है! : पी
योदा

1

आपको लूप करना है, और लूप में होना है, लूप को एक अलग फ़ंक्शन में स्थानांतरित करने के लिए क्लीनर है।

मैंने इससे निपटने के लिए एक विस्तार विधि बनाई। यह अपवाद का पीछा करते हुए, निर्दिष्ट प्रकार के सभी आंतरिक अपवादों की एक सूची देता है। InnerException और AggregateException.InnerException।

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

public static class ExceptionExtensions
{
    public static IEnumerable<T> innerExceptions<T>(this Exception ex)
        where T : Exception
    {
        var rVal = new List<T>();

        Action<Exception> lambda = null;
        lambda = (x) =>
        {
            var xt = x as T;
            if (xt != null)
                rVal.Add(xt);

            if (x.InnerException != null)
                lambda(x.InnerException);

            var ax = x as AggregateException;
            if (ax != null)
            {
                foreach (var aix in ax.InnerExceptions)
                    lambda(aix);
            }
        };

        lambda(ex);

        return rVal;
    }
}

उपयोग बहुत सरल है। यदि, उदाहरण के लिए, आप जानना चाहते हैं कि क्या हमने सामना किया

catch (Exception ex)
{
    var myExes = ex.innerExceptions<MyException>();
    if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error")))
    {
        // ...
    }
}

किस बारे में है Exception.GetBaseException()?
किकेनेट

1

आप कहीं एक उपयोगिता वर्ग में एक विधि बनाने के लिए पुनरावृत्ति का उपयोग कर सकते हैं।

public Exception GetFirstException(Exception ex)
{
    if(ex.InnerException == null) { return ex; } // end case
    else { return GetFirstException(ex.InnerException); } // recurse
}

उपयोग:

try
{
    // some code here
}
catch (Exception ex)
{
    Exception baseException = GetFirstException(ex);
}

विस्तार विधि का सुझाव दिया (अच्छा विचार @dtb)

public static Exception GetFirstException(this Exception ex)
{
    if(ex.InnerException == null) { return ex; } // end case
    else { return GetFirstException(ex.InnerException); } // recurse
}

उपयोग:

try
{
    // some code here
}
catch (Exception ex)
{
    Exception baseException = ex.GetFirstException();
}

उपयोगी public static Exception GetOriginalException(this Exception ex) { if (ex.InnerException == null) return ex; return ex.InnerException.GetOriginalException(); }
क्रिकेनेट

लागू नहीं होता AggregateException.InnerExceptions?
कीकनेट

0

एक और तरीका है कि आप इसे GetBaseException()दो बार कॉल कर सकते हैं :

Exception innermostException = e.GetBaseException().GetBaseException();

यह काम करता है क्योंकि यदि यह एक है AggregateException, तो पहली कॉल आपको अंतरतम में मिलती है- AggregateExceptionफिर दूसरी कॉल आपको उस अपवाद के अंतरतम अपवाद पर मिलती है। यदि पहला अपवाद कोई नहीं है AggregateException, तो दूसरा कॉल उसी अपवाद को वापस करता है।


0

मैं इसमें भाग गया और अपवाद "स्टैक" से सभी अपवाद संदेशों को सूचीबद्ध करने में सक्षम होना चाहता था। इसलिए, मैं इसे लेकर आया हूं।

public static string GetExceptionMessages(Exception ex)
{
    if (ex.InnerException is null)
        return ex.Message;
    else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}";
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.