c# - एक बार में कई अपवादों को पकड़ो?



.net exception exception-handling (21)

In c# 6.0,Exception Filters is improvements for exception handling

try
{
    DoSomeHttpRequest();
}
catch (System.Web.HttpException e)
{
    switch (e.GetHttpCode())
    {
        case 400:
            WriteLine("Bad Request");
        case 500:
            WriteLine("Internal Server Error");
        default:
            WriteLine("Generic Error");
    }
}

यह System.Exception पकड़ने के लिए निराश है। System.Exception । इसके बजाए, केवल "ज्ञात" अपवादों को पकड़ा जाना चाहिए।

अब, यह कभी-कभी अनपेक्षित दोहराव कोड की ओर जाता है, उदाहरण के लिए:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
    WebId = Guid.Empty;
}
catch (OverflowException)
{
    WebId = Guid.Empty;
}

मुझे आश्चर्य है: क्या दोनों अपवादों को पकड़ने का एक तरीका है और केवल WebId = Guid.Empty कॉल को कॉल करें?

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


@Micheal

आपके कोड का थोड़ा संशोधित संस्करण:

catch (Exception ex)
{
   Type exType = ex.GetType();
   if (exType == typeof(System.FormatException) || 
       exType == typeof(System.OverflowException)
   {
       WebId = Guid.Empty;
   } else {
      throw;
   }
}

स्ट्रिंग तुलना बदसूरत और धीमी हैं।


स्वीकृत उत्तर स्वीकार्य लगता है, सिवाय इसके कि कोडएनालिसिस / एफएक्सकॉप इस तथ्य के बारे में शिकायत करेगा कि यह एक सामान्य अपवाद प्रकार को पकड़ रहा है।

साथ ही, ऐसा लगता है कि "है" ऑपरेटर थोड़ा प्रदर्शन को कम कर सकता है।

सीए 1800: अनावश्यक रूप से "ऑपरेटर के रूप में 'के परिणाम का परीक्षण करने पर विचार न करें , लेकिन यदि आप ऐसा करते हैं, तो आप प्रत्येक अपवाद को अलग से पकड़ने के बजाय अधिक कोड लिखेंगे।

वैसे भी, मैं यही करूँगा:

bool exThrown = false;

try
{
    // Something
}
catch (FormatException) {
    exThrown = true;
}
catch (OverflowException) {
    exThrown = true;
}

if (exThrown)
{
    // Something else
}

यह मैट के उत्तर का एक रूप है (मुझे लगता है कि यह थोड़ा क्लीनर है) ... एक विधि का उपयोग करें:

public void TryCatch(...)
{
    try
    {
       // something
       return;
    }
    catch (FormatException) {}
    catch (OverflowException) {}

    WebId = Guid.Empty;
}

कोई अन्य अपवाद फेंक दिया जाएगा और कोड WebId = Guid.Empty; हिट नहीं किया जाएगा। यदि आप अन्य अपवादों को अपने प्रोग्राम को क्रैश नहीं करना चाहते हैं, तो बस इसे दो अन्य कैच के बाद जोड़ें:

...
catch (Exception)
{
     // something, if anything
     return; // only need this if you follow the example I gave and put it all in a method
}

सावधान और चेतावनी: फिर भी एक और तरह, कार्यात्मक शैली।

लिंक में क्या है सीधे आपके प्रश्न का उत्तर नहीं देता है, लेकिन इसे देखने के लिए इसे विस्तारित करना मुश्किल है:

static void Main() 
{ 
    Action body = () => { ...your code... };

    body.Catch<InvalidOperationException>() 
        .Catch<BadCodeException>() 
        .Catch<AnotherException>(ex => { ...handler... })(); 
}

(मूल रूप से एक और खाली Catch अधिभार प्रदान करता है जो खुद को लौटाता है)

इस के लिए बड़ा सवाल यही है । मुझे नहीं लगता कि लागत यहां लाभ से अधिक है :)


संपादित करें: मैं दूसरों के साथ सहमत हूं जो कह रहे हैं कि, सी # 6.0 के रूप में, अपवाद फ़िल्टर अब जाने का एक बिल्कुल बढ़िया तरीका है: catch (Exception ex) when (ex is ... || ex is ... )

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

catch (Exception ex) when (
    ex is ...
    || ex is ...
    || ex is ...
)

मूल:

मुझे पता है कि मैं पार्टी के लिए थोड़ा देर हो चुकी हूं, लेकिन पवित्र धुआं ...

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

private void TestMethod ()
{
    Action<Exception> errorHandler = ( ex ) => {
        // write to a log, whatever...
    };

    try
    {
        // try some stuff
    }
    catch ( FormatException  ex ) { errorHandler ( ex ); }
    catch ( OverflowException ex ) { errorHandler ( ex ); }
    catch ( ArgumentNullException ex ) { errorHandler ( ex ); }
}

मैं मदद नहीं कर सकता लेकिन आश्चर्य ( चेतावनी: आगे थोड़ा विडंबना / कटाक्ष) पृथ्वी पर क्यों मूल रूप से निम्नलिखित को प्रतिस्थापित करने के लिए इस प्रयास में जाते हैं:

try
{
    // try some stuff
}
catch( FormatException ex ){}
catch( OverflowException ex ){}
catch( ArgumentNullException ex ){}

... इस अगली कोड गंध के कुछ पागल बदलाव के साथ, मेरा मतलब है उदाहरण के लिए, केवल यह दिखाने के लिए कि आप कुछ कीस्ट्रोक सहेज रहे हैं।

// sorta sucks, let's be honest...
try
{
    // try some stuff
}
catch( Exception ex )
{
    if (ex is FormatException ||
        ex is OverflowException ||
        ex is ArgumentNullException)
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

क्योंकि यह निश्चित रूप से स्वचालित रूप से अधिक पठनीय नहीं है।

अनुमोदित, मैंने /* write to a log, whatever... */ return; के तीन समान उदाहरण /* write to a log, whatever... */ return; पहले उदाहरण से बाहर।

लेकिन यह मेरा मुद्दा है। आपने कार्यों / विधियों के बारे में सुना है, है ना? गंभीरता से। एक सामान्य ErrorHandler फ़ंक्शन लिखें और, जैसे प्रत्येक कैच ब्लॉक से इसे कॉल करें।

यदि आप मुझसे पूछते हैं, तो दूसरा उदाहरण ( if और कीवर्ड के साथ) दोनों काफी कम पठनीय हैं, और साथ ही आपके प्रोजेक्ट के रखरखाव चरण के दौरान अधिक त्रुटि-प्रवण हैं।

रखरखाव चरण, जो प्रोग्रामिंग के लिए अपेक्षाकृत नया हो सकता है, आपके प्रोजेक्ट के कुल जीवनकाल में 98.7% या अधिक शामिल होगा, और रखरखाव करने वाले गरीब schmuck लगभग निश्चित रूप से आपके अलावा कोई अन्य होने जा रहा है। और एक बहुत अच्छा मौका है कि वे आपके नाम को शाप देने वाले नौकरी पर अपना 50% समय व्यतीत करेंगे।

और निश्चित रूप से FxCop आप पर छाल डालता है और इसलिए आपको अपने कोड में एक विशेषता भी जोड़नी है जो चल रहे प्रोग्राम के साथ वास्तव में ज़िप करने के लिए है, और केवल एक समस्या को अनदेखा करने के लिए FxCop को बताने के लिए है कि 99.9% मामलों में यह पूरी तरह से है फ़्लैगिंग में सही है। और, क्षमा करें, मुझे गलत हो सकता है, लेकिन क्या यह "अनदेखा" विशेषता वास्तव में आपके ऐप में संकलित नहीं होती है?

if एक पंक्ति पर परीक्षण इसे और अधिक पठनीय बनाता है if पूरा कर देगा? मुझे ऐसा नहीं लगता। मेरा मतलब है, मेरे पास एक और प्रोग्रामर जोरदार बहस करता था कि एक बार बहुत पहले एक लाइन पर अधिक कोड डालने से यह "तेजी से दौड़ जाएगा।" लेकिन निश्चित रूप से वह कठोर नट्स था। उसे समझाते हुए (सीधे चेहरे के साथ - जो चुनौतीपूर्ण था) कैसे दुभाषिया या कंपाइलर उस लंबी लाइन को अलग-अलग एक-निर्देश-प्रति-पंक्ति विवरणों के अलावा तोड़ देगा - अनिवार्य रूप से परिणाम के समान अगर वह आगे बढ़ गया था और संकलक को बाहर निकालने की कोशिश करने के बजाए कोड को पठनीय बना दिया - उसके ऊपर कोई प्रभाव नहीं पड़ा। लेकिन मैं पीछे हटा।

जब आप तीन और अपवाद प्रकार, एक महीने या दो जोड़ते हैं तो यह कितना कम पठनीय होता है? (उत्तर: यह बहुत कम पठनीय हो जाता है)।

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

बस केह रहा हू...

// super sucks...
catch( Exception ex )
{
    if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException )
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

System.Exception पकड़ो। System.Exception और प्रकारों पर स्विच करें

catch (Exception ex)            
{                
    if (ex is FormatException || ex is OverflowException)
    {
        WebId = Guid.Empty;
        return;
    }

    throw;
}

पूर्णता के लिए, चूंकि .NET 4.0 कोड को फिर से लिखा जा सकता है:

Guid.TryParse(queryString["web"], out WebId);

TryParse कभी अपवाद फेंकता नहीं है और प्रारूप गलत है, तो WebId को Guid.Empty सेट करना गलत है।

चूंकि सी # 7 आप एक अलग रेखा पर एक चर को पेश करने से बच सकते हैं:

Guid.TryParse(queryString["web"], out Guid webId);

आप लौटने वाले टुपल्स को पार्स करने के तरीकों को भी बना सकते हैं, जो अभी तक संस्करण 4.6 के रूप में .NET Framework में उपलब्ध नहीं हैं:

(bool success, Guid result) TryParseGuid(string input) =>
    (Guid.TryParse(input, out Guid result), result);

और इन्हें इस तरह इस्तेमाल करें:

WebId = TryParseGuid(queryString["web"]).result;
// or
var tuple = TryParseGuid(queryString["web"]);
WebId = tuple.success ? tuple.result : DefaultWebId;

इस बेकार जवाब के लिए अगला बेकार अपडेट तब आता है जब बाहर पैरामीटर का निर्माण सी # 12. में लागू किया जाता है :)


Just call the try and catch twice.

try
{
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
    WebId = Guid.Empty;
}
try
{
    WebId = new Guid(queryString["web"]);
}
catch (OverflowException)
{
    WebId = Guid.Empty;
}

It is just that Simple!!


Maybe try to keep your code simple such as putting the common code in a method, as you would do in any other part of the code that is not inside a catch clause?

उदाहरण के लिए:

try
{
    // ...
}
catch (FormatException)
{
    DoSomething();
}
catch (OverflowException)
{
    DoSomething();
}

// ...

private void DoSomething()
{
    // ...
}

Just how I would do it, trying to find the simple is beautiful pattern


With C# 7 the answer from Michael Stum can be improved while keeping the readability of a switch statement:

catch (Exception ex)
{
    switch (ex)
    {
        case FormatException _:
        case OverflowException _:
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}

So you´re repeating lots of code within every exception-switch? Sounds like extracting a method would be god idea, doesn´t it?

So your code comes down to this:

MyClass instance;
try { instance = ... }
catch(Exception1 e) { Reset(instance); }
catch(Exception2 e) { Reset(instance); }
catch(Exception) { throw; }

void Reset(MyClass instance) { /* reset the state of the instance */ }

I wonder why no-one noticed that code-duplication.

From C#6 you furthermore have the exception-filters as already mentioned by others. So you can modify the code above to this:

try { ... }
catch(Exception e) when(e is Exception1 || e is Exception2)
{ 
    Reset(instance); 
}

जोसेफ डाइगल का जवाब एक अच्छा समाधान है, लेकिन मुझे निम्न संरचना को थोड़ा सा और कम त्रुटि प्रवण होने के लिए मिला।

catch(Exception ex)
{   
    if (!(ex is SomeException || ex is OtherException)) throw;

    // Handle exception
}

अभिव्यक्ति को बदलने के कुछ फायदे हैं:

  • एक वापसी कथन आवश्यक नहीं है
  • कोड घोंसला नहीं है
  • यूसुफ के समाधान में अभिव्यक्ति से अलग किए गए 'फेंक' या 'रिटर्न' बयान को भूलने का कोई खतरा नहीं है।

इसे एक लाइन से भी संकुचित किया जा सकता है (हालांकि बहुत सुंदर नहीं)

catch(Exception ex) { if (!(ex is SomeException || ex is OtherException)) throw;

    // Handle exception
}

संपादित करें: सी # 6.0 में अपवाद फ़िल्टरिंग सिंटैक्स को थोड़ा क्लीनर बना देगा और किसी भी मौजूदा समाधान पर कई अन्य लाभों के साथ आता है। (सबसे विशेष रूप से ढेर बेकार छोड़कर)

यहां बताया गया है कि सी # 6.0 सिंटैक्स का उपयोग करने में एक ही समस्या कैसी दिखाई देगी:

catch(Exception ex) when (ex is SomeException || ex is OtherException)
{
    // Handle exception
}

catch (Exception ex)
{
    if (!(
        ex is FormatException ||
        ex is OverflowException))
    {
        throw;
    }
    Console.WriteLine("Hello");
}

जैसा कि अन्य ने इंगित किया है, यह निर्धारित करने के लिए कि आपके पास क्या हो रहा है यह निर्धारित करने के लिए आपके कैच ब्लॉक के अंदर एक कथन हो सकता है। सी # 6 अपवाद फ़िल्टर का समर्थन करता है, इसलिए निम्नलिखित काम करेंगे:

try { … }
catch (Exception e) when (MyFilter(e))
{
    …
}

MyFilter विधि तब कुछ इस तरह दिख सकती है:

private bool MyFilter(Exception e)
{
  return e is ArgumentNullException || e is FormatException;
}

वैकल्पिक रूप से, यह सब इनलाइन किया जा सकता है (जब कथन का दायां हाथ सिर्फ बुलियन अभिव्यक्ति होना चाहिए)।

try { … }
catch (Exception e) when (e is ArgumentNullException || e is FormatException)
{
    …
}

यह catch ब्लॉक के भीतर से एक कथन का उपयोग करने से अलग है, अपवाद फ़िल्टर का उपयोग करके स्टैक को अनदेखा नहीं किया जाएगा

आप इसे देखने के लिए विजुअल स्टूडियो 2015 डाउनलोड कर सकते हैं।

यदि आप विजुअल स्टूडियो 2013 का उपयोग करना जारी रखना चाहते हैं, तो आप निम्न nuget पैकेज स्थापित कर सकते हैं:

इंस्टॉल-पैकेज Microsoft.Net.Compilers

लिखने के समय, इसमें सी # 6 के लिए समर्थन शामिल होगा।

इस पैकेज को संदर्भित करने से प्रोजेक्ट को सी # के विशिष्ट संस्करण और पैकेज में निहित विजुअल बेसिक कंपाइलर्स का उपयोग करके बनाया जाएगा, क्योंकि किसी भी सिस्टम स्थापित संस्करण के विपरीत।


Since I felt like these answers just touched the surface, I attempted to dig a bit deeper.

So what we would really want to do is something that doesn't compile, say:

// Won't compile... damn
public static void Main()
{
    try
    {
        throw new ArgumentOutOfRangeException();
    }
    catch (ArgumentOutOfRangeException)
    catch (IndexOutOfRangeException) 
    {
        // ... handle
    }

The reason we want this is because we don't want the exception handler to catch things that we need later on in the process. Sure, we can catch an Exception and check with an 'if' what to do, but let's be honest, we don't really want that. (FxCop, debugger issues, uglyness)

So why won't this code compile - and how can we hack it in such a way that it will?

If we look at the code, what we really would like to do is forward the call. However, according to the MS Partition II, IL exception handler blocks won't work like this, which in this case makes sense because that would imply that the 'exception' object can have different types.

Or to write it in code, we ask the compiler to do something like this (well it's not entirely correct, but it's the closest possible thing I guess):

// Won't compile... damn
try
{
    throw new ArgumentOutOfRangeException();
}
catch (ArgumentOutOfRangeException e) {
    goto theOtherHandler;
}
catch (IndexOutOfRangeException e) {
theOtherHandler:
    Console.WriteLine("Handle!");
}

The reason that this won't compile is quite obvious: what type and value would the '$exception' object have (which are here stored in the variables 'e')? The way we want the compiler to handle this is to note that the common base type of both exceptions is 'Exception', use that for a variable to contain both exceptions, and then handle only the two exceptions that are caught. The way this is implemented in IL is as 'filter', which is available in VB.Net.

To make it work in C#, we need a temporary variable with the correct 'Exception' base type. To control the flow of the code, we can add some branches. यहाँ जाता हैं:

    Exception ex;
    try
    {
        throw new ArgumentException(); // for demo purposes; won't be caught.
        goto noCatch;
    }
    catch (ArgumentOutOfRangeException e) {
        ex = e;
    }
    catch (IndexOutOfRangeException e) {
        ex = e;
    }

    Console.WriteLine("Handle the exception 'ex' here :-)");
    // throw ex ?

noCatch:
    Console.WriteLine("We're done with the exception handling.");

The obvious disadvantages for this are that we cannot re-throw properly, and -well let's be honest- that it's quite the ugly solution. The uglyness can be fixed a bit by performing branch elimination, which makes the solution slightly better:

Exception ex = null;
try
{
    throw new ArgumentException();
}
catch (ArgumentOutOfRangeException e)
{
    ex = e;
}
catch (IndexOutOfRangeException e)
{
    ex = e;
}
if (ex != null)
{
    Console.WriteLine("Handle the exception here :-)");
}

That leaves just the 're-throw'. For this to work, we need to be able to perform the handling inside the 'catch' block - and the only way to make this work is by an catching 'Exception' object.

At this point, we can add a separate function that handles the different types of Exceptions using overload resolution, or to handle the Exception. Both have disadvantages. To start, here's the way to do it with a helper function:

private static bool Handle(Exception e)
{
    Console.WriteLine("Handle the exception here :-)");
    return true; // false will re-throw;
}

public static void Main()
{
    try
    {
        throw new OutOfMemoryException();
    }
    catch (ArgumentException e)
    {
        if (!Handle(e)) { throw; }
    }
    catch (IndexOutOfRangeException e)
    {
        if (!Handle(e)) { throw; }
    }

    Console.WriteLine("We're done with the exception handling.");

And the other solution is to catch the Exception object and handle it accordingly. The most literal translation for this, based on the context above is this:

try
{
    throw new ArgumentException();
}
catch (Exception e)
{
    Exception ex = (Exception)(e as ArgumentException) ?? (e as IndexOutOfRangeException);
    if (ex != null)
    {
        Console.WriteLine("Handle the exception here :-)");
        // throw ?
    }
    else 
    {
        throw;
    }
}

So to conclude:

  • If we don't want to re-throw, we might consider catching the right exceptions, and storing them in a temporary.
  • If the handler is simple, and we want to re-use code, the best solution is probably to introduce a helper function.
  • If we want to re-throw, we have no choice but to put the code in a 'Exception' catch handler, which will break FxCop and your debugger's uncaught exceptions.

Note that I did find one way to do it, but this looks more like material for The Daily WTF :

catch (Exception ex)
{
    switch (ex.GetType().Name)
    {
        case "System.FormatException":
        case "System.OverflowException":
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}

कैसा रहेगा

try
{
    WebId = Guid.Empty;
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
}
catch (OverflowException)
{
}

2015-12-15 अपडेट करें: सी # 6 के लिए https://.com/a/22864936/1718702 देखें। यह एक क्लीनर और अब भाषा में मानक है।

उन लोगों के लिए गियर किया गया जो एक बार पकड़ने और अपवाद फ़िल्टर करने के लिए एक अधिक सुरुचिपूर्ण समाधान चाहते हैं, मैं नीचे दिखाए गए एक विस्तार विधि का उपयोग करता हूं।

मेरे पास पहले से ही मेरी लाइब्रेरी में यह एक्सटेंशन था, मूल रूप से अन्य उद्देश्यों के लिए लिखा गया था, लेकिन यह अपवादों पर type जांच के लिए पूरी तरह से काम करता था। इसके अलावा, इमो, यह एक समूह की तुलना में क्लीनर दिखता है || बयान। इसके अलावा, स्वीकार्य उत्तर के विपरीत, मैं स्पष्ट अपवाद हैंडलिंग पसंद करता हूं इसलिए ex is ... अवांछित व्यवहार था क्योंकि वंचित कक्षाएं माता-पिता के प्रकार के लिए असाइन की जा सकती हैं)।

प्रयोग

if (ex.GetType().IsAnyOf(
    typeof(FormatException),
    typeof(ArgumentException)))
{
    // Handle
}
else
    throw;

IsAnyOf.cs एक्सटेंशन (निर्भरता के लिए उदाहरण को पूरा करने में पूर्ण त्रुटि देखें)

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter matches at least one of the passed in comparisons.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_comparisons">Values to compare against.</param>
        /// <returns>True if a match is found.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static bool IsAnyOf<T>(this T p_parameter, params T[] p_comparisons)
        {
            // Validate
            p_parameter
                .CannotBeNull("p_parameter");
            p_comparisons
                .CannotBeNullOrEmpty("p_comparisons");

            // Test for any match
            foreach (var item in p_comparisons)
                if (p_parameter.Equals(item))
                    return true;

            // Return no matches found
            return false;
        }
    }
}

पूर्ण त्रुटि हैंडलिंग उदाहरण (नई कंसोल ऐप पर कॉपी-पेस्ट करें)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.FluentValidation;

namespace IsAnyOfExceptionHandlerSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // High Level Error Handler (Log and Crash App)
            try
            {
                Foo();
            }
            catch (OutOfMemoryException ex)
            {
                Console.WriteLine("FATAL ERROR! System Crashing. " + ex.Message);
                Console.ReadKey();
            }
        }

        static void Foo()
        {
            // Init
            List<Action<string>> TestActions = new List<Action<string>>()
            {
                (key) => { throw new FormatException(); },
                (key) => { throw new ArgumentException(); },
                (key) => { throw new KeyNotFoundException();},
                (key) => { throw new OutOfMemoryException(); },
            };

            // Run
            foreach (var FooAction in TestActions)
            {
                // Mid-Level Error Handler (Appends Data for Log)
                try
                {
                    // Init
                    var SomeKeyPassedToFoo = "FooParam";

                    // Low-Level Handler (Handle/Log and Keep going)
                    try
                    {
                        FooAction(SomeKeyPassedToFoo);
                    }
                    catch (Exception ex)
                    {
                        if (ex.GetType().IsAnyOf(
                            typeof(FormatException),
                            typeof(ArgumentException)))
                        {
                            // Handle
                            Console.WriteLine("ex was {0}", ex.GetType().Name);
                            Console.ReadKey();
                        }
                        else
                        {
                            // Add some Debug info
                            ex.Data.Add("SomeKeyPassedToFoo", SomeKeyPassedToFoo.ToString());
                            throw;
                        }
                    }
                }
                catch (KeyNotFoundException ex)
                {
                    // Handle differently
                    Console.WriteLine(ex.Message);

                    int Count = 0;
                    if (!Validate.IsAnyNull(ex, ex.Data, ex.Data.Keys))
                        foreach (var Key in ex.Data.Keys)
                            Console.WriteLine(
                                "[{0}][\"{1}\" = {2}]",
                                Count, Key, ex.Data[Key]);

                    Console.ReadKey();
                }
            }
        }
    }
}

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter matches at least one of the passed in comparisons.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_comparisons">Values to compare against.</param>
        /// <returns>True if a match is found.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static bool IsAnyOf<T>(this T p_parameter, params T[] p_comparisons)
        {
            // Validate
            p_parameter
                .CannotBeNull("p_parameter");
            p_comparisons
                .CannotBeNullOrEmpty("p_comparisons");

            // Test for any match
            foreach (var item in p_comparisons)
                if (p_parameter.Equals(item))
                    return true;

            // Return no matches found
            return false;
        }

        /// <summary>
        /// Validates if any passed in parameter is equal to null.
        /// </summary>
        /// <param name="p_parameters">Parameters to test for Null.</param>
        /// <returns>True if one or more parameters are null.</returns>
        public static bool IsAnyNull(params object[] p_parameters)
        {
            p_parameters
                .CannotBeNullOrEmpty("p_parameters");

            foreach (var item in p_parameters)
                if (item == null)
                    return true;

            return false;
        }
    }
}

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter is not null, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void CannotBeNull(this object p_parameter, string p_name)
        {
            if (p_parameter == null)
                throw
                    new
                        ArgumentNullException(
                        string.Format("Parameter \"{0}\" cannot be null.",
                        p_name), default(Exception));
        }
    }
}

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter is not null or an empty collection, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static void CannotBeNullOrEmpty<T>(this ICollection<T> p_parameter, string p_name)
        {
            if (p_parameter == null)
                throw new ArgumentNullException("Collection cannot be null.\r\nParameter_Name: " + p_name, default(Exception));

            if (p_parameter.Count <= 0)
                throw new ArgumentOutOfRangeException("Collection cannot be empty.\r\nParameter_Name: " + p_name, default(Exception));
        }

        /// <summary>
        /// Validates the passed in parameter is not null or empty, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentException"></exception>
        public static void CannotBeNullOrEmpty(this string p_parameter, string p_name)
        {
            if (string.IsNullOrEmpty(p_parameter))
                throw new ArgumentException("String cannot be null or empty.\r\nParameter_Name: " + p_name, default(Exception));
        }
    }
}

Two Sample NUnit Unit Tests

Matching behaviour for Exception types is exact (ie. A child IS NOT a match for any of its parent types).

using System;
using System.Collections.Generic;
using Common.FluentValidation;
using NUnit.Framework;

namespace UnitTests.Common.Fluent_Validations
{
    [TestFixture]
    public class IsAnyOf_Tests
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void IsAnyOf_ArgumentNullException_ShouldNotMatch_ArgumentException_Test()
        {
            Action TestMethod = () => { throw new ArgumentNullException(); };

            try
            {
                TestMethod();
            }
            catch (Exception ex)
            {
                if (ex.GetType().IsAnyOf(
                    typeof(ArgumentException), /*Note: ArgumentNullException derrived from ArgumentException*/
                    typeof(FormatException),
                    typeof(KeyNotFoundException)))
                {
                    // Handle expected Exceptions
                    return;
                }

                //else throw original
                throw;
            }
        }

        [Test, ExpectedException(typeof(OutOfMemoryException))]
        public void IsAnyOf_OutOfMemoryException_ShouldMatch_OutOfMemoryException_Test()
        {
            Action TestMethod = () => { throw new OutOfMemoryException(); };

            try
            {
                TestMethod();
            }
            catch (Exception ex)
            {
                if (ex.GetType().IsAnyOf(
                    typeof(OutOfMemoryException),
                    typeof(Exception)))
                    throw;

                /*else... Handle other exception types, typically by logging to file*/
            }
        }
    }
}

Wanted to added my short answer to this already long thread. Something that hasn't been mentioned is the order of precedence of the catch statements, more specifically you need to be aware of the scope of each type of exception you are trying to catch.

For example if you use a "catch-all" exception as Exception it will preceed all other catch statements and you will obviously get compiler errors however if you reverse the order you can chain up your catch statements (bit of an anti-pattern I think) you can put the catch-all Exception type at the bottom and this will be capture any exceptions that didn't cater for higher up in your try..catch block:

            try
            {
                // do some work here
            }
            catch (WebException ex)
            {
                // catch a web excpetion
            }
            catch (ArgumentException ex)
            {
                // do some stuff
            }
            catch (Exception ex)
            {
                // you should really surface your errors but this is for example only
                throw new Exception("An error occurred: " + ex.Message);
            }

I highly recommend folks review this MSDN document:

Exception Hierarchy


try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

एफवाईआई अन्य अपवादों के बाद अन्य खंड जा सकता है और केवल तभी चलाया जाएगा जब प्रयास में कोड अपवाद का कारण नहीं बनता है।





c# .net exception exception-handling