Using finally after catching exceptions - C#

An exception is an applications response to an exceptional circumstance, that needs to be specially handled.

We can specify how the exception is handled by catching the exception:

string name = null;

try
{
	Console.WriteLine(name.ToUpper());
}
catch (NullReferenceException e)
{
	// The name variable is null! We should do something.
	// i.e. Present the user with a validation message.
}

This can go one of two ways.

  • If we supply a value to name before calling name.ToUpper(), then the code will execute and there will be no exception.
  • If we leave name assigned to null, name.ToUpper() will throw a NullReferenceException, and we will enter the catch block.

What is the finally keyword?

But what if we have code that needs to run, whether an exception is thrown or not?

This is where the finally keyword is used.

The finally block is used to execute a set of statements at the end of a try-catch. These statements will be executed directly after the try, if the code ran successfully, or directly after the catch if an exception was caught.

We'll look at a common example of where you would might use finally; Ensuring that when you open a file, as it should always be closed.

Using Finally

Let's look at an example of where we might want to always execute code after a try-catch:

using System;
using System.IO;

class TryCatchFinallyExceptions 
{
    public static void Main (string[] args) 
    {
        StreamReader reader = null;  
        var fileName = "logs.txt";

        try
        {
            reader = new StreamReader(File.Open(fileName, System.IO.FileMode.Open));

            while (reader.Peek() != -1)  
            {  
                Console.WriteLine(reader.ReadLine());  
            }  
        }
        catch(Exception e)
        {   
            Console.WriteLine($"Code threw the exception: {e.GetType()}");
            Console.WriteLine(e.Message);
        }
        finally
        {
            Console.WriteLine("Finished");
            if (reader != null)  
            {  
                reader.Close();  
            } 
        }
    }
}

In this example, we open a StreamReader within the try block, with a given file name, then write each line from the document to the console:

try 
{
	reader = new StreamReader(File.Open(fileName, System.IO.FileMode.Open));

	while (reader.Peek() != -1)  
	{  
		Console.WriteLine(reader.ReadLine());  
	} 
}

If we were to encounter an exception in this block (for instance, the fileName might refer to a path that does not exist), then the exception would be caught and handled correctly.

However, we've opened a file! We need to close it and free up resources, whether the code ran successfully or not.

Fortunately, we close it in the finally block:

finally
{
	Console.WriteLine("Finished");
	if (reader != null)  
	{  
		reader.Close();  
	} 
}