Pluralsight Logo
Author avatar

Peter Mbanguo

Author badge Author

Throw and Re-throw Exceptions in C#

Peter Mbanguo

Author BadgeAuthor
  • Oct 18, 2018
  • 7 Min read
  • 15 Views
  • Oct 18, 2018
  • 7 Min read
  • 15 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. Regardless of the cause of the problem, the end result is that the application does not work as expected. At this point, we say the application has encountered an error. In .NET, exceptions are thrown when a running application encounters an error.

What Are Exceptions?

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.

Throwing Exceptions

When a situation occurs that violates a system or application constraint, it can generate an exception to signal to the caller that an operation has failed. The process of generating and signaling the error is referred to as throwing exception. This is done using the throw keyword followed by a new instance of a class deriving from System.Exception. Let's look at an example. Create a new console project and update Program.cs with the code below.

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
using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var radio = new Radio();
            radio.SetVolume(120);
        }

        class Radio
        {
            public int Volume { get; set; }
            public string Station { get; set; }

            public void SetVolume(int volume)
            {
                if (volume > 100)
                {
                    throw new ArgumentOutOfRangeException(nameof(volume), "volume cannot be more than 100");
                }

                Volume = volume;
            }

            public void SetStation(string station)
            {
                if (string.IsNullOrEmpty(station))
                {
                    throw new ArgumentNullException(nameof(station), "you cannot tune to an empty station");
                }

                Station = station;
            }
        }
    }
}

In the code example above, we defined a Radio class, the properties Station and Volume, and methods SetStation and SetVolume. When the SetVolume method is called with a value greater than 100, the application throws an ArgumentOutOfRangeException with the parameter name and exception message as arguments. Similarly, when SetStation method is called with an empty string, it throws an ArgumentNullException with the parameter name and exception message as arguments.

If we run the application and it crashes, it will print out the exception message and stack trace tells us where the error occurred in the console. The information that it'll give you should be similar to what is displayed in the image below:

throw exception.png

From the stack trace information, you can see that it points to the line where we used the throw keyword, followed by the line that called the SetVolume method. This information is very helpful when debugging.

Re-throwing Exceptions

The exception from the previous section propagates up the call stack and since we have no code to catch and handle the exception, it crashes. When an exception is caught, we can perform some operations, like logging the error, and then re-throw the exception. Re-throwing an exception means calling the throw statement without an exception object, inside a catch block. It can only be used inside a catch block.

Let's create a new console application and update the Program.cs file 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
37
38
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());

            Console.WriteLine(calculator.Divide(number, divisor));
        }

        class Calculator
        {
            public int Divide(int number, int divisor)
            {
                try
                {
                    return number / divisor;
                }
                catch (DivideByZeroException)
                {
                    //TODO: log error
                    Console.WriteLine("Can't divide by 0");
                    throw;//propage this error
                }

            }
        }
    }
}

From the code above, we have a Calculator class with Divide method. In .NET, when a number is being divided by 0, it throws the DivideByZeroException. In the Divide method, we have code to catch this exception, log to the console, and re-throw the exception. Run the application and enter a divisor of 0:

re-throw exception.gif

You can see that when we passed it 0 as a divisor, it printed Can't divide by 0 to the console before re-throwing the exception. Notice that the stack trace still maintained proper information, pointing to line 26 as the line that the error occurred at, even though it was re-thrown on line 32. A common mistake people make when they intend to re-throw exception is to call the throw keyword with the caught exception object. An example of this is as follows:

1
2
3
4
5
6
catch (DivideByZeroException ex)
{
    //TODO: log error
    Console.WriteLine("Can't divide by 0");
    throw ex;//propage this error
}

If we had it implemented this way, it'll print out the following stack trace:

1
2
3
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at MyApp.Program.Calculator.Divide(Int32 number, Int32 divisor) in /Users/pmbanugo/Documents/projects/dotnet/MyApp/Program.cs:line 32
   at MyApp.Program.Main(String[] args) in /Users/pmbanugo/Documents/projects/dotnet/MyApp/Program.cs:line 17

You can see that it pointed to line 32, the line where the exception was thrown, rather than where it occurred. Re-throwing an exception is simply calling throw without an exception object.

That's a Wrap

Sometimes an error occurs in our application because of bad code, other times, it is caused by bad user input that has not been accounted for in the application’s code. An exception is thrown when an error is encountered in a running application. In this guide we looked at using the throw keyword for throwing and re-throwing exception and explained the correct syntax for re-throwing exception.

1