×

Search anything:

Exception Handling in C#

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

What is exception handling?

Simply put, exception handling is used as a preventative measure to handle an error that might otherwise crash the entire program. An example could look like this: the program tries to open a file that doesn't exist. Without exception handling, this very likely would cause a crash. Using exception handling, we could instead create the file it is trying to open, give an error message to the user, log the error, or however else you wish to handle the exception. Another advantage using exception handling is the ability to release resources, such as removing an object.

Exception Handling in C# uses the keywords try, catch (optional), and finally (optional). These will be covered more in-depth with code examples below. Note that while exception handling is incredibly useful and has little impact on performance (until an exception is encountered), it should only be used when necessary to maintain clean code.

When do I want to use exception handling?

Exception handling should be used whenever you are dealing with code that is prone to error. The following are common examples:

  • File handling - Usually any time you are working with files and/or directories, exception handling is extremely useful in overcoming common errors.
  • User input/controls - As any seasoned programmer knows, user errors are extremely common. Exception handling, usually used in conjunction with other checking methods (such as using if/else statements), is used to handle any unforseen errors the end-user may make, such as using numbers where letters are supposed to be.
  • Debugging - Exception handling is EXTREMELY useful in debugging if you are experiencing a problematic code block that isn't easily replicatable. It's commonly used to log errors, which is especially useful if the problematic code has no "rhyme or reason" when it crashes.
  • Networking/API calls - It's common use to wrap any network / API calls into a handling block so if anything fails along the way, the exception can be caught and handled. These calls are known to hang or fail altogether, so using exception handling is crucial to avoid a crash during those moments.

Basically, anything you write that you could see having unexpected results, use exception handling. It's a priceless tool in any programmers belt that, when used correctly, can help stability and prevent unnecessary crashing/bugs.

How do I use exception handling?

Usage of exception handling is fairly simple. As stated earlier, the three keyword to remember are try, catch, and finally. So what do these keywords mean?

  • try - This block is where you will want to put all the code that is to be tested for exceptions. As stated earlier, only include what you feel is problematic code as you want to maintain as much clean code as possible.
  • catch (optional) - This block is where you do the actual handling. This can include logging errors/variables, invoking a different method instead, outputting an error message, and so on as your heart desires. Important to note about catch is that this can be called multiple times for various different exceptions. This works on a top-down calling structure and will be shown in examples below.
  • finally (optional) - This block will typically only be used to clean up any resources, such as removing an object or closing a file. Note that this will always execute, even if no exceptions occur. Any exceptions that do get caught by a catch will have it's catch block executed first.

Here is a simple example of a try/catch. This will catch the error and display it to the console. Note here we are catching all exceptions with the Exception parameter in the catch block. In a following example, you will see how we can be more selective with what exceptions are caught.

try
{
    File.Open("test.txt", FileMode.Open);
}
catch (Exception ex)
{
    Console.WriteLine(ex);
}

Running this will provide you with the entire call stack the exception runs through. It will look something like this:

System.IO.FileNotFoundException: Could not find file "/app/test.txt"
File name: '/app/test.txt'
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x0019e] in <533173d24dae460899d2b10975534bb0>:0
.......

Take note that the actual exception it catches is System.IO.FileNotFoundException. This will be used later to demonstrate how we can handle specific exceptions.

Another, much more truancated, way of getting exception information is using the Message property of Exception, as showing in the WriteLine below:

// Part of iq.opengenus.org
try
{
    File.Open("test.txt", FileMode.Open);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

Running this will now only provide the following information:

Could not find file "/app/test.txt"

You can see the results are dramatically different with one providing more information yet less direct about the problem.

As hinted upon earlier, you can specify exactly what type of exception you are looking to catch, and even add in multiple exceptions! In our example, the actual exception is System.IO.FileNotFoundException, or simply FileNotFoundException. Note this works on a top-down principal so in our example here, FileNotFoundException is caught before Exception.

Let's see how we can do that!

try
{
    File.Open("test.txt", FileMode.Open);
}
catch (DirectoryNotFoundException ex)
{
    // This will not be run since the directory is found but IS checked before
    // FileNotFoundException
    Console.WriteLine(ex.Message);
}
catch (FileNotFoundException ex)
{
    // This triggers, as the file is not here and is 'caught' first.
    Console.WriteLine("The file isn't here.");
}
catch (Exception ex)
{
    // This does not run since it was already caught above.
    Console.WriteLine(ex.Message);
}

This will now provide the output

The file isn't here.

Note that both DirectoryNotFoundException nor Exception were triggered as the exception was handled with our FileNotFoundException catch statement.

As noted, finally is used to release resources. In this example, we create a StreamReader of the file, attempt to write a line from it, then close the file.

// Note this assumes "Test.txt" exists.
StreamReader file = new("Test.txt");

try
{
    Console.WriteLine(file.ReadLine());
}
catch (IOException ex)
{
    Console.WriteLine(ex.Message);
}
finally
{
    if (file != null)
    {
        file.Close();
    }
}

Lastly, you can also do a try/finally if you don't intend on catching exceptions.

// Note this assumes "Test.txt" exists.
StreamReader file = new("Test.txt");

try
{
    Console.WriteLine(file.ReadLine());
}
finally
{
    if (file != null)
    {
        file.Close();
    }
}

In conclusion of this article at OpenGenus, Exception Handling is a very powerful feature that any program should learn to use on a regular basis. I hope you now have a better understanding of how/when to use it. With proper implementing, this will make your programs much more stable and more informative when something does go wrong.

Troy Martin

Troy Martin

Agoraphobic programmer who has been self-teaching himself programming for 5 years. Experienced in C++/C#/Python. Game developer as well, working with Unity, Unreal Engine 5, and GameMaker Studio 2.

Read More

Improved & Reviewed by:


OpenGenus Tech Review Team OpenGenus Tech Review Team
Exception Handling in C#
Share this