How to catch exceptions - C#

While it is important to throw exceptions in unexpected circumstances, throwing an exception and not handling it is far from ideal.

To catch an exception, we first need to encapsulate the code that may throw the exception within a try block, as follows:

try
{
	// Execute any code that may throw an exception in here
}

To handle any exceptions, we need to add a catch block:

try
{
	// Execute any code that may throw an exception in here
}
catch(Exception e)
{
	// Handle the exception here
}

Extending a previous example

In the last article, we looked at How to throw exceptions.

Let's revisit the example in that article, where we threw an exception if the method was supplied with null:

public static void Main (string[] args) 
{
	PrintName(null);
	
	Console.WriteLine("Goodbye!");
}

static void PrintName(string name)
{
	if(name == null)
	{
		throw new NullReferenceException("Name is null");
	}

	if(name.Length == 0)
	{
		throw new ArgumentException("Name should not be empty");
	}

	Console.WriteLine($"Hello {name}!");
}
Unhandled Exception:
System.NullReferenceException: Name is null
  at CatchingExceptions.PrintName (System.String name) [0x00006] in <40a39de507ca40d281b8163477e0239e>:0 
  at CatchingExceptions.Main (System.String[] args) [0x00000] in <40a39de507ca40d281b8163477e0239e>:0 

There's two things to notice here:

  • The exception is unhandled. This means that, although we're throwing a perfectly valid exception, the application does not know which steps to take next.
  • As a result, the line to write "Goodbye!" to the console isn't executed.

Catching the exception

To catch the exception, we can wrap the method call in try, catch braces:

public static void Main (string[] args) 
{
	try
	{
		PrintName(null);
	}
	catch
	{
		Console.WriteLine("Something went wrong.");
	}
	
	Console.WriteLine("Goodbye!");
}

static void PrintName(string name)
{
	if(name == null)
	{
		throw new NullReferenceException("Name is null");
	}

	if(name.Length == 0)
	{
		throw new ArgumentException("Name should not be empty");
	}

	Console.WriteLine($"Hello {name}!");
}
Something went wrong.
Goodbye!

Now that we've caught the exception, we can deal with it appropriately (although in this instance, we only wrote some output to the console).

Using multiple catch statements

But wait, what went wrong exactly?

Now that we've caught the exception, we've swallowed up the original message that was with the exception, so this is no longer being printed to the console:

Name is null

Not only does this make debugging a nightmare, but we're not handling the instances where the name is null, and when the name is empty separately.

To do so, we need to specify a catch statement for each scenario:

public static void Main (string[] args) 
{
	try
	{
		PrintName(null);
	}
	catch(NullReferenceException e)
	{
		Console.WriteLine("No name was supplied!");
	}
	catch(ArgumentException e)
	{
		Console.WriteLine($"We were unable to get your name!");
	}

	Console.WriteLine("Goodbye!");
}

static void PrintName(string name)
{
	if(name == null)
	{
		throw new NullReferenceException("Name is null");
	}

	if(name.Length == 0)
	{
		throw new ArgumentException("Name should not be empty");
	}

	Console.WriteLine($"Hello {name}!");
}

This allows us to handle each type of exception that is thrown within the try.