- Home
- .NET tutorials
- When does the try, catch and finally code blocks run in C#?
When does the try, catch and finally code blocks run in C#?
Published: Monday 17 June 2024
The try, catch and finally statements are excellent for catching unhandled exceptions. They are also good for ensuring that a code block always runs regardless of whether an exception is thrown or not.
The purpose of the try block
The purpose of the try block is to write code where there is a risk of an exception being thrown.
catch statement ensures that these exceptions can be handled without the application crashing.
var httpClient = new HttpClient();
try
{
var response = await httpClient.GetAsync("https://www.roundthecode.com/api/products/1");
response.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Exception classes
In the code snippet above, we were catching the exception if it uses the Exception class. As all exceptions inherit this class, it will always catch any exception thrown.
ArgumentException- One of the arguments provided to a method is not validDivideByZeroException- Attempting to divide a number by zeroIndexOutOfRangeException- Attempting to get the value of an array index that is outside the bounds of the arrayNullReferenceException- Using a null reference object in a way that requires an instance, such as calling a property or a methodOutOfMemoryException- The application can not allocated enough memory
Any of these exceptions can be handled in a separate catch code block.
NullReferenceException is thrown:
public class CategoryService
{
public string? GetCategoryName(Category category)
{
try
{
return category.Name;
}
catch (NullReferenceException)
{
return null;
}
}
}
However, if any other exceptions are thrown, they would be unhandled.
catch code blocks to a try statement. In this example, if the exception thrown is a NullReferenceException, the method will return null. If any other exceptions are thrown, the exception is written to the console and then the method returns null.
public class CategoryService
{
public string? GetCategoryName(Category category)
{
try
{
return category.Name;
}
catch (NullReferenceException)
{
// Code block will only be run if a NullReferenceException is thrown in the 'try' code block
return null;
}
catch (Exception ex)
{
// Code block will run if anything except a NullReferenceException is thrown in the 'try' code block
Console.WriteLine(ex.Message);
return null;
}
}
}
How to write your own Exception class
There may be instances when you want to write your own exception class. This can be done by creating a class and inheriting the Exception class.
CategoryException class. We've included three of the base classes with constructors that:
- Are parameterless
- Has a message as a string as a parameter
- Has a message as a string and an inner exception as parameters
In-addition, we are passing in the category name and it's being saved as a read-only property as part of the exception.
public class CategoryException : Exception
{
public string CategoryName { get; }
public CategoryException(string categoryName)
: base()
{
// Does not add an error message
CategoryName = categoryName;
}
public CategoryException(string categoryName, string message)
: base(message)
{
// Add an error message through the base 'Exception' class
CategoryName = categoryName;
}
public CategoryException(string categoryName, string message, Exception? innerException)
: base(message, innerException)
{
// Add an error message and inner exception through the base 'Exception' class
CategoryName = categoryName;
}
}
If we wish to catch this exception, we can add it to our try, catch statement.
public class CategoryService
{
public string? GetCategoryName(Category category)
{
try
{
return category.Name;
}
catch (CategoryException)
{
return null;
}
catch (NullReferenceException)
{
return null;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
}
When do the code blocks run?
Now that we've established how the try, catch statement works, that's examine when they run and how the finally statement works.
No exception in try block
var load = true;
try
{
var a = 9 + 9;
}
catch (Exception ex)
{
// Does not run as there is no exception
}
finally
{
// Runs after the try code block
load = false;
}
There's a try code block that doesn't throw an exception. We are catching any exception, but not doing anything with it.
try block will execute, but as no exception is thrown, it will ignore the catch block and go straight to the finally block.
Exception is thrown in the try block
var load = true;
try
{
var a = int.Parse("not a number"); // FormatException thrown
var b = 9 + 9; // This does not run as an exception has already been thrown
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // Will write the FormatException to the Console
}
finally
{
// Runs after the catch code block
load = false;
}
In this situation, the try block will run up until the point there is an exception.
"not a number" is not a valid integer, it will throw a FormatException. As the exception is thrown before the b variable is declared, that code snippet will not run.
finally block will run after the catch block has been executed.
Exception is thrown but not the one being catched
var load = true;
try
{
var a = int.Parse("not a number"); // FormatException thrown
var b = 9 + 9; // This does not run as an exception has already been thrown
}
catch (NullReferenceException ex)
{
// This code block will not run as it's a FormatException being thrown
Console.WriteLine(ex.Message);
}
finally
{
// Runs after the try code block in an ASP.NET Core app, but not a Console application
load = false;
}
The try block is throwing the same FormatException.
NullReferenceException type. So the catch block won't run and the application will throw an exception instead.
finally block if it's an ASP.NET Core app. If it's a console application, it stops before it has a chance to run the finally block.
Exception is thrown in the catch block
var load = true;
try
{
var a = int.Parse("not a number"); // FormatException thrown
var b = 9 + 9; // This does not run as an exception has already been thrown
}
catch (Exception ex)
{
// Throws the exception causing the application to throw an exception
throw ex;
}
finally
{
// Runs after the catch code block in an ASP.NET Core, but not in a Console application
load = false;
}
When the try block throws the FormatException, it will execute the catch block.
catch block is also being thrown, the application will throw an exception.
finally block will run before the application throws an exception in an ASP.NET Core app. But in a Console application, it will not run as the application would have already stopped.
No catch block
var load = true;
try
{
var a = int.Parse("not a number"); // FormatException thrown
var b = 9 + 9; // This does not run as an exception has already been thrown
}
finally
{
// Runs after the try code block in an ASP.NET Core application, but not a Console application
load = false;
}
We have no catch statement and the FormatException is being thrown in the try statement.
catch block, the finally block will still run in an ASP.NET Core app. But like with the other scenarios, the Console application will stop before it can run the finally block.
Exception thrown in the finally block
var load = true;
try
{
var a = int.Parse("not a number"); // FormatException thrown
var b = 9 + 9; // This does not run as an exception has already been thrown
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // Will write the FormatException message to the Console
}
finally
{
var c = int.Parse("not a number"); // FormatException thrown
load = false; // This does not run as an exception has already been thrown
}
The FormatException gets thrown in the try block.
finally block will still run. However, a FormatException is thrown when we try to pass the integer with a non-numeric string.
load boolean will not be changed to false.
Watch the video
Watch our video where we go through the try, catch and finally code blocks, what exceptions are available, how to write your own custom exception and when the code blocks run.
Catch runs if there is an exception. Finally always runs
In conclusion, the catch statement will only run if an exception is thrown in the try block, and it's the same exception declared in the catch statement.
finally statement will always run, regardless of whether an exception is thrown in a try or catch block, or whether that exception is handled or not.
finally statement doesn't run if an unhandled exception occurs.
Related tutorials
SOLID principles in C# used in object-oriented design
SOLID principles in C#, looking at design principles and examples for using object-oriented design (OOD) in your software.