In this article, we are going to learn about different ways to catch multiple exceptions in C#. Utilizing try-catch
block is the best way to manage exceptions. It also enables developers to manage exceptions however they want. Using a single catch block is one of the models which we can use to control exceptions.
Lets’s start.
Catching Multiple Exceptions Separately
If we want to handle the exceptions separately and make a particular decision for each one, we should have specific information about the exceptions that may occur. In this case, the best way is to use an individual catch block for each exception.
To be precise, let’s suppose we want to take two numbers from the user and then divide the first one by the other. Due to the string format of the input values, we should convert them to a numerical form. But if something goes wrong, we want to show the end-user a reason for the failed operation.
Let’s create the MultipleCatches
method to do that:
public static int MultipleCatches(string numeratorParam, string denominatorParam) { try { var numerator = Convert.ToUInt32(numeratorParam); var denominator = Convert.ToUInt32(denominatorParam); return (int)(numerator / denominator); } catch (FormatException) { Console.WriteLine("Format Exception!"); } catch (DivideByZeroException) { Console.WriteLine("Divide By Zero Exception!"); } catch (OverflowException) { Console.WriteLine("Overflow Exception!"); } return -1; }
While converting parameters to an unsigned integer type with the Convert.ToUInt32
method, our application may throw two exceptions FormatException
or OverflowException
. The division line also may throw a DivideByZeroException
. So, we’ve handled all the potential exceptions that can happen in this case.
Catching Multiple Exceptions in a Single Catch Block
Sometimes, we need to do the same work for all the exceptions. To do that, we use the single-catch-block model and group the type of exceptions we want to handle.
Let’s create a SingleCatchWithWhen
method to explore this model:
public static int SingleCatchWithWhen(string numeratorParam, string denominatorParam) { try { var numerator = Convert.ToUInt32(numeratorParam); var denominator = Convert.ToUInt32(denominatorParam); return (int)(numerator / denominator); } catch (Exception ex) when (ex is FormatException || ex is DivideByZeroException || ex is OverflowException) { return -1; } }
In this method, we pack all the potential exceptions at one catch
block using the when
keyword. It is a shorter way to declare exceptions to the catch
block.
Separating Exceptions in a Single Catch Block
To show the way to separate exceptions in a single catch block, let’s create the SingleCatchSwitchCase
method:
public static int SingleCatchSwitchCase(string numeratorParam, string denominatorParam) { try { var numerator = Convert.ToUInt32(numeratorParam); var denominator = Convert.ToUInt32(denominatorParam); return (int)(numerator / denominator); } catch (Exception ex) { switch (ex) { case FormatException: Console.WriteLine("Format Exception!"); break; case DivideByZeroException: Console.WriteLine("Divide By Zero Exception!"); break; case OverflowException: Console.WriteLine("Overflow Exception!"); break; } } return -1; }
We catch all the exceptions in a single catch block and separate them using a switch-case
pattern. Fortunately, switch (ex)
can recognize the type of the ex
variable and compare it with each case
. On the other hand, we can also use the if-else
pattern instead of a switch-case
model.
To separately manage all exceptions in one catch block, we can utilize the switch
pattern syntax too.
So, let’s create the SingleCatchSwitchPattern
method to explain it:
public static int SingleCatchSwitchPattern(string numeratorParam, string denominatorParam) { try { var numerator = Convert.ToUInt32(numeratorParam); var denominator = Convert.ToUInt32(denominatorParam); return (int)(numerator / denominator); } catch (Exception ex) { string str = ex switch { FormatException => "Format Exception!", DivideByZeroException => "Divide By Zero Exception!", OverflowException => "Overflow Exception!", _ => "Unknown Exception!" }; Console.WriteLine(str); } return -1; }
In our method, the lambda
expressions and _
case match and filter all values. We use this model to generate an appropriate message for each exception. In the str
variable, we keep the selected string to print on the console.
Multiple Catch Blocks vs Single Catch Blocks
Once the application throws the exception the question is, do multiple catch blocks have better performance or a single catch block? In fact, after throwing an exception, the try-catch
should have a switching pattern for delivering the exception to the first best case. When we use multiple catch blocks, the compiler defines the switching model automatically. But if we write a single catch block, we should specify that switching pattern manually.
At this time, both patterns may have the same performance if the developer utilizes a fast decision-maker model in the catch block. What does it mean? It means, when the developer uses a slow flow controller like an if-else
model to manage exceptions, they cannot expect to achieve the same performance as the multiple catch blocks. But fast flow controllers such as switch-case
and switch-when
models can be as fast as multiple catch blocks.
Conclusion
So, in this article, we’ve learned how to catch multiple exceptions using different approaches. We’ve seen that we can use the when keyword to achieve that and also combine it with the switch-case expression.