How to throw exceptions - C#

We can use exceptions to indicate when an error has occurred when running our application. Some of these exceptions will be created by the CLR (Common Language Runtime) to handle typical errors.

You will also want to create your own exceptions, in order to correctly handle exceptional situations.

To raise an exception, we need to first create it, then throw it.

Let's first take a look at an exception thrown by the CLR.

Making .NET throw an exception

Here's a simple example of causing an exception to be thrown by the CLR (and upsetting mathematicians at the same time):

public static void Main (string[] args) 
{
    CLRException();
}

static int CLRException()
{
    return 100 / int.Parse("0");
}
Unhandled Exception:
System.DivideByZeroException: Attempted to divide by zero.
  at ThrowingExceptions.CLRException () [0x0000c] in <699faf0287d64e16b2473362c3f1c46f>:0 
  at ThrowingExceptions.Main (System.String[] args) [0x00000] in <699faf0287d64e16b2473362c3f1c46f>:0 

In this instance, a specific exception of type DivideByZeroException was thrown.

Creating and throwing an exception

To create a simple exception, we simply need to use the new keyword:

Exception myException = new Exception("Exception message goes here");

Then, to throw it, we need to use the throw keyword:

throw myException;

Often, when you see an exception being thrown, the exception will be created at the same time:

throw new Exception("Exception message goes here");

So we could create a method that throws an exception like this:

public static void Main (string[] args) 
{
    BasicThrow();
}

static void BasicThrow()
{
    throw new Exception("Boom");
}
Unhandled Exception:
System.Exception: Boom
  at ThrowingExceptions.Main (System.String[] args) [0x00000] in <7d8747c5c5214c88a0a5bdfd61bc130c>:0 

Throwing different types of exceptions

In the first example, the CLR threw an exception of type DivideByZeroException, whereas we threw a basic Exception.

The DivideByZeroException inherits from the Exception base class, and using it provides two main advantages:

  • The developer viewing the error log can see the type of exception, and will have a clearer understanding of where the error occurred and why.
  • By throwing a specific type, we can catch exceptions of that type, and handle them differently.

Let's take a look at an example where we might want to throw an exception:

public static void Main (string[] args)
{
    PrintName(null);
}

static void PrintName(string name)
{
    Console.WriteLine($"Hello {name}!");
}
Hello !

If we get into a situation where null is supplied, we can choose to throw an exception of type NullReferenceException:

public static void Main (string[] args)
{
    PrintName(null);
}

static void PrintName(string name)
{
    if(name == null)
    {
        throw new NullReferenceException("Name is null");
    }
    
    Console.WriteLine($"Hello {name}!");
}
Unhandled Exception:
System.NullReferenceException: Name is null
  at ThrowingExceptions.PrintName (System.String name) [0x00006] in <7a216e743c0c4e79b69871a21f412080>:0 
  at ThrowingExceptions.Main (System.String[] args) [0x00000] in <7a216e743c0c4e79b69871a21f412080>:0 

However, what happens if we supply an empty string to the method?

Since an empty string is not null, we should handle that separately:

public static void Main (string[] args)
{
    PrintName(String.Empty);
}

static void PrintName(string name)
{
    if(name == null)
    {
        throw new NullReferenceException("Name is null");
    }
    
    if(name.Length == 0)
    {
        throw new Exception("Name should not be empty");
    }
    
    Console.WriteLine($"Hello {name}!");
}
Unhandled Exception:
System.Exception: Name should not be empty
  at ThrowingExceptions.PrintName (System.String name) [0x0001c] in <069beacd1c4f447dbdd584a2d047ce2e>:0 
  at ThrowingExceptions.Main (System.String[] args) [0x00000] in <069beacd1c4f447dbdd584a2d047ce2e>:0