How to catch all types of exception in one single catch block?

14,989

Solution 1

To handle all exception, use Exception class.

try
{

}
catch(Exception ex)
{
     switch (ex.GetType().ToString())
     {
         case "System.InvalidOperationException":
              //cast ex to specific type of exception to use it's properties
              ((InvalidOperationException)ex).SomeMethod();
         break;
         case "System.NotSupportedException":
             ((System.NotSupportedException)ex).AnotherMethod();
         break;
         case "System.Web.Services.Protocols.SoapException":
             ((System.Web.Services.Protocols.SoapException)ex).OtherMethod();
         break;
     }

}

Why can't you just use multiple catch block anyway?

Solution 2

User2808350 is correct that try catch blocks can have many different catches for a reason, however sometimes you find you are repeating yourself (DRY) when using this pattern.

An alternative that can result in concise, readable code is to use the is operator which evaluates to true if your exception is an instance of a particular type or one that derives from that type. Unfortunately it's not possible to use the is operator in a switch block, so you have to use if-then-else.

Here is an example where I test the exception type and set the exit code accordingly.

try
{
    // try something
}
catch (Exception e)
{
    if (e is FileNotFoundException)
        Environment.ExitCode = 2;
    else if (e is InvalidOperationException)
        Environment.ExitCode = 1;
    else
        Environment.ExitCode = 42;
    throw;
}

Solution 3

This is now a language feature. Just use a switch/case statement

The asker's first attempt, shown commented out in the code snippet in the question, is now the easiest and in my opinion best way to do this.

I actually came across this question while trying to figure out what Resharper had done with one of its suggested improvements. I'm still not 100% sure on the terminology involved as the only documentation I could find was explaining Discards and only mentions in passing the "pattern matching with the is and switch keywords" that is also being performed.

I had started, as Onkel-j reccomends, with a chain of 'if ex is Type':

try
{
    doWork();
}
catch (Exception ex)
{
    if (ex is SpecificExceptionType)
    {
        //todo
    }
    else 
    {
        //etc
    }
}

but resharper suggested I let it change this to a switch/case:

try
{
    doWork();
}
catch (Exception ex)
{
    switch (ex)
    {
        case SpecificExceptionType _:
            //todo
            break;            
        default:
            //etc
            break;
    }
}

Resharper has used Discards to do a sort of automatic is and toss out the unused variable. If you need to actually use the exception as the specific type, give it a name in place of the underscore:

try
{
    doWork();
}
catch (Exception ex)
{
    switch (ex)
    {
        case SpecificExceptionType specific:
            HandleSpecificException(specific);
            break;            
        default:
            //etc
            break;
    }
}

Or to answer the original question:

catch(Exception ex)
{
    //do what you want here
    
    switch(ex)
    {
        case System.Web.Services.Protocols.SoapException soapEx:        
            if (soapEx.Code.Name.Equals("Client"))
            {
                  msg = "service's function not exist";
            }
            else if (soapEx.Code.Name.Equals("Server"))
            {
                 msg = "function error"
            }
            else
            {
                 msg = "unknown";
            }
            MessageBox.Show(msg, "error", MessageBoxButtons.OK);    
            break;
        case System.Net.WebException webEx:
            switch (webEx.Status)
            {
               case System.Net.WebExceptionStatus.ConnectFailure:
                    //do some thing
                    break;
               case System.Net.WebExceptionStatus.Timeout:
                    //do some thing
                    break;
                case System.Net.WebExceptionStatus.ProtocolError:
                    switch (((System.Net.HttpWebResponse)webEx.Response).StatusCode)
                    {
                        case System.Net.HttpStatusCode.NotFound:
                            //do some thing
                            break;
                        case System.Net.HttpStatusCode.ServiceUnavailable:
                            //do some thing
                            break;
                        case System.Net.HttpStatusCode.Unauthorized:
                            //do some thing
                            break;
                        default:
                            //do some thing
                            break;
                    }
                    break;
                default:
                    //do some thing
                    break;
            }
            break;
        default:
            //etc
            break;
    }
}

Solution 4

Should use

try {

    ....

}
catch (System.Net.HttpStatusCode.NotFound)
{
 //do some thing
}    
catch (System.Net.HttpStatusCode.ServiceUnavailable)
{
 //do some thing
}

catch (System.Net.HttpStatusCode.Unauthorized)
{
 //do some thing
}

catch (System.Net.HttpStatusCode.NotFound)
{
 //do some thing
}    
catch (Exception)
{
 //do some thing
}

It's better that using swicth

Share:
14,989
user1299527
Author by

user1299527

Updated on June 23, 2022

Comments

  • user1299527
    user1299527 almost 2 years
    catch(Exception ex)
    {
        //do what you want here
    
        //When type of exception is System.Web.Services.Protocols.SoapException
        //if (ex.Code.Name.Equals("Client"))
        //{
        //      msg = "service's function not exist";
        //}
        //else if (ex.Code.Name.Equals("Server"))
        //{
        //     msg = "function error"
        //}
        //else
        //{
        //     msg = "unknown";
        //}
        //MessageBox.Show(msg, "error", MessageBoxButtons.OK);
    
    **But ex is not System.Web.Services.Protocols.SoapException so I cannot call ex.Code.Name.Equals("Client")**
    
    
    //When System.Net.WebException
    //switch (ex.Status)
    //{
    //   case System.Net.WebExceptionStatus.ConnectFailure:
    //              do some thing
                    break;
    //   case System.Net.WebExceptionStatus.Timeout:
                    //do some thing
                    break;
    //    case System.Net.WebExceptionStatus.ProtocolError:
                switch (((System.Net.HttpWebResponse)ex.Response).StatusCode)
                {
                      case System.Net.HttpStatusCode.NotFound:
                            //do some thing
                            break;
                        case System.Net.HttpStatusCode.ServiceUnavailable:
                            //do some thing
                            break;
                        case System.Net.HttpStatusCode.Unauthorized:
                            //do some thing
                            break;
                        default:
                            //do some thing
                            break;
                    }
                    break;
                default:
                    //do some thing
                    break;
            }
    }
    

    But Exception is not System.Net.WebException. So cannot call ex.Status

    My problem:

    I have a Smartclient software include WindowsForm as client and a webservice as server. Client and Server both are n-tiers application I have tested and found that has any problem when call service from Client

    1. in app.config: service's path wrrong . I catch System.NotSupportedException
    2. Or when the server cannot connect: System.Net.WebExceptionStatus
    3. Server's webconfig is wrong : System.InvalidOperationException
    4. Service throws an exception: System.Web.Services.Protocols.SoapException ...

    My Idea

    I call the Exception that as representative of all other exception types is representativeAlException I have namespace : Common and two classese representativeAlException.cs and BusinessExceptionHandler.cs

    Make a common function with a param as (representativeAlException ex)

                try
                {
                    Err_LogCheck.Service1.Service1 service = new Err_LogCheck.Service1.Service1();
                    return service.getDeviceByZero(ZERO);
                }
                catch (Common.representativeAlException ex)
                {
                    Common.BusinessExceptionHandler.ProcessException(ex);
                }
    

    What I want to do

    Where the service is called. Only one catch block can handler for all type of Exception

    in ProcessException(representativeAlException ex) function

    switch (ex)
    {
    case System.InvalidOperationException:
     //Do some thing
     break;
    case System.NotSupportedException:
     //Do some thing
     break;
    case System.Web.Services.Protocols.SoapException:
     //do some thing
     break;
    ...
    ...
    
    • kazinix
      kazinix over 11 years
      Try my answer, I cast ex to specific exception so you can use the methods and properties of that specific exception.
    • Enigmativity
      Enigmativity over 11 years
      Seriously, don't do a catch-all exception block. It's a bad programming practice. Only catch specific exceptions.
    • user1299527
      user1299527 over 11 years
      i do catch-all in any where. But the exception is separated to any type in a common function
  • user1299527
    user1299527 over 11 years
    ex is not Exception. "I call the Exception that as representative of all other exception types is representativeAlException". My catch block is : catch (Common.representativeAlException ex)
  • kazinix
    kazinix over 11 years
    Your question is not clear so I assumed you want to handle all types of exception. I'm trying to help but all I get is downvote.
  • user1299527
    user1299527 over 11 years
    i am sorry because of my bad english. I want to do that: where the webservice is called, using only one catch block instead of many catch block for many exception types. And in my common function, i will check type of exception and send each message to end-user
  • kazinix
    kazinix over 11 years
    Have you tried my codes, it's meant to catch all types of exception.
  • siride
    siride over 11 years
    This is the answer, best as I can tell, based on the question. I'm not sure why it got downvoted.
  • Kirk Woll
    Kirk Woll over 11 years
    @dpp, your answer is OK, but it would be better to use the syntax that was designed for this. Get rid of the exception type altogether. i.e. try {} catch {}. C# does not require you to specify the exception you are trying to catch.
  • user1299527
    user1299527 over 11 years
    i written alot. But cannot post my answer. So sorry
  • Kirk Woll
    Kirk Woll over 11 years
    @user1299527, I understand that English is not your first language, but reading "i written alot. But cannot post my answer. So sorry" I do not understand what you are getting at.
  • user1299527
    user1299527 over 11 years
    thank you. I have edited my question's content. Hope that you can understand my question
  • kazinix
    kazinix over 11 years
    SoapException is derived from SystemException which is derived from Exception, is it not? Why couldn't the try-catch block catch the SoapException?
  • user1299527
    user1299527 over 11 years
    SoapException : SystemException, SystemException : Exception. But if catch (Exception ex) so ex has not properties of SoapException. I think catch Exception can catch any exception types but can not using Exception as SoapException when catch with Exception instead of SoapException
  • kazinix
    kazinix over 11 years
    No, no, no. ex will have the properties of SoapException if the exception catched is SoapException, we are just using Exception so that we can catch different types of exception.
  • kazinix
    kazinix over 11 years
    @user1299527 Try the codes above, cast ex to specific exception so you can use the properties of that specific exception.
  • user1299527
    user1299527 over 11 years
    dpp , i want to vote you. But cannot. Because of not enough reputation. thank! If Using multiple catch block, i have to write many code in any where the service is called. Only one catch block. And i build a common function. To detach the type of exception. And return the best message to end-user.
  • kazinix
    kazinix over 11 years
    It's okay, you're welcome. It's not about the votes anyway. :)
  • kazinix
    kazinix over 11 years
    Just check my post as answer when you can.
  • kazinix
    kazinix over 11 years
    there's a white check on the upper left part of my post, just check it, if you can't just leave it, it's fine with me.
  • Tamas Molnar
    Tamas Molnar over 8 years
    Upvoting, because mentioning the DRY principle. Which is why I ended up doing it this way.
  • Felini
    Felini about 6 years
    This doesn't answer original question, neither any proof for "this way is better" was provided.
  • Felini
    Felini about 6 years
    I think this could be improved with usage of nameof() - removes lack of typing when checking for matches.
  • Felini
    Felini about 6 years
    Reading this exact code is noticeably harder compared to switch statements, which can be inlined due to short lines. While this is not wrong, I doubt using "is" is worth the added reading complexity.