Pluralsight Logo
Author avatar

Peter Mbanguo

Author badge Author

Catching and Wrapping Exceptions

Peter Mbanguo

Author BadgeAuthor
  • Oct 22, 2018
  • 7 Min read
  • 10 Views
  • Oct 22, 2018
  • 7 Min read
  • 10 Views
C#

Introduction

Writing software is a complex undertaking, and it is quite common for even the best software to ship with various problems. Sometimes the problem is caused by bad code; other times, a problem is caused by bad user input that has not been accounted for in the application’s code, for example, an age input field being assigned the value Julia as value. Regardless of the cause of the problem, the end result is that the application does not work as expected.

An exception is a runtime error in a program that violates a system or application constraint, or a condition that is not expected to occur during normal execution of the program. Possible exceptions include attempting to connect to a database that no longer exists, when a program tries to divide a number by zero, or opening a corrupted XML file. When these occur, the system catches the error and raises an exception.

Catching Exceptions

Catching exceptions is a way of handling these unexpected errors by defining a block of code that will be run when the exceptions are thrown. This code block is known as an exception handler. In the absence of an exception handler, your application will stop (crash) and present your user with a very unfriendly error message. The purpose of exception handling is to respond to exceptions with one or more of the following:

  1. Display a user-friendly message to your users.
  2. Log information about the exception so that it can be addressed by the support team.
  3. Take some corrective actions to allow the program to continue running without crashing.

Exception handling uses the try keyword to try actions that may not succeed, catch keyword to handle failures when you decide that it is reasonable to do so, and finally keyword to clean up resources afterward.

Let's work with an example. Create a new console application and update Program.cs with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var calculator = new Calculator();

            Console.WriteLine("Enter number");
            int number = int.Parse(Console.ReadLine());

            Console.WriteLine("Enter divisor");
            int divisor = int.Parse(Console.ReadLine());

            try
            {
                calculator.Divide(number, divisor);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Oh no, Something is wrong");
                Console.WriteLine(ex);
            }
        }

        class Calculator
        {
            public int Divide(int number, int divisor)
            {
                return number / divisor;
            }
        }
    }
}

The code above accepts a number and divisor from the user and calls the Divide method with those values. We guarded line 19 in case of any error. If an exception occurs inside the try block, the application handles it by running the code within the catch block. In .NET, dividing a number by zero causes a DivideByZeroException. Therefore, if we run the application with zero as a divisor, we get the following result printed in the console.

catching exceptions.png

The application prints the above message and exits normally, without crashing. You can see that it was the DivideByZeroException encountered when running the division operation.

Catching And Wrapping Exceptions

Sometimes it may be beneficial to wrap the original exception in a new type of exception and then throw that new type of exception. This essentially allows us to change the new type of exception that gets propagated up the call stack. This change may help clarify the exception to the higher level application if it is not explicit for the higher level catch block to handle. A useful application of this is if you’re developing a library for other programmers to use, your library might work with some low-level code, which exceptions encountered in the low-level code might be hard for the library users to handle. In that scenario, we can catch exceptions that occur when performing these low-level operations, and wrap them in a custom exception or some other exception type that the library users or higher level code can understand and handle.

Following on from our previous example, suppose we decide that the DivideByZeroException is not explicit enough for us to handle, we can wrap it in a different exception and propagate that up the call stack. Let's update Program.cs with the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;

namespace MyApp
{
  class Program
  {
      static void Main(string[] args)
      {
          var calculator = new Calculator();

          Console.WriteLine("Enter number");
          int number = int.Parse(Console.ReadLine());

          Console.WriteLine("Enter divisor");
          int divisor = int.Parse(Console.ReadLine());

          try
          {
              calculator.Divide(number, divisor);
          }
          catch (ArithmeticException ex)
          {
              Console.WriteLine("Oh no, Something is wrong");
              Console.WriteLine(ex);
          }
      }

      class Calculator
      {
          public int Divide(int number, int divisor)
          {
              try
              {
                  return number / divisor;
              }
              catch (DivideByZeroException ex)
              {
                  //propage this error
                  throw new ArithmeticException("Can't divide by 0. Please use a different number as divisor", ex);
              }
          }
      }
  }
}

From the code above, we changed the catch block on line 21 to handle the ArithmeticException exception type. We wrapped the division operation, inside the Divide method, in a try/catch block. Inside the catch block is where we catch the DivideByZeroException type and wrapped it inside the ArithmeticException type. Wrapping exception simply involves setting the InnerException property of the new exception to propagate up the call stack, to the caught exception. Doing this maintains the exception call stack information.

Run the application and enter a divisor of zero when asked. It should print the following when the exception is thrown:

wrapping exceptions.png

You can see that the caught exception was the ArithmeticException and it had the defined error message. The information from the call stack pointed to line 34, where it encountered the error.

Summary

An exception is thrown when an error is encountered in a running application. When an exception occurs, the program halts the normal execution, generates an exception object with information about the error, and propagates the exception up the call stack. If there’s no code to catch and handle the exception, it stops the program from running (i.e it crashes). We need an exception handler to catch and handle the exception. Finally, we looked at using the catch keyword and how to wrap an exception in order to propagate a more specific exception up the call stack.

1