Exceptions catching / handling / throwing

Exceptions catching / handling / throwing

When I started coding c# over more than 15 years ago it was common practice to use Exceptions for handling errors, also internally.

So, instead of returning pure error messages with indicators if a method suceeded (see my Tuples article here), Exceptions had been thrown.

Now, Exceptions are not anymore that nice when it comes to:

  • program flow (some exception is thrown somewhere and catched 4 times up the call stack)
  • they are 'cost intensive' - which does mean they require some ressources
  • call stack or inner exceptions are lost if not handled correctly

But they are great to use when something really worse happend for your application and you cannot continue.

Short introduction

Exceptions?

When an exception is thrown, the following program code is not executed anymore (beside there is a finally block) until it is catched. If it is not catched somewhere, the program is terminated.

// we just want one method throwing the exception
private void ExcSample()
{
  throw Exception("foo");
}

// 
public static void Main()
{
   // will result in termination of the program as no exception will be catched
   ExcSample();

   // will catch the exception in the catch block and write the message to console
   try
   {
      ExcSample();
   }
   catch(Exception exc)
   {
      Console.WriteLine($"Error occured: {exc.Message}");
   }

   // example with finally block
   try
   {
      ExcSample();
   }
   catch(Exception exc)
   {
      Console.WriteLine($"Error occured: {exc.Message}");
   }
   finally 
   {
      // code here would be always executed: if an exception does occur or if not
   }

   // also possible, only finally
   try
   {
      ExcSample();
   }
   finally 
   {
      // code here would be always executed: if an exception does occur or if not
   }
}

Custom or user-defined exceptions

Custom or user-defined exceptions are exceptions which have been created by yourself. The decision to create own exceptions may be due to additional requirements for the Exception itself (e. g. localization or for logic operations where no existing Exception may fit your needs.

Exceptions can be simply created by deriving your new Exception class from the base class or any other Exception class:

public class MyOwnException : Exception
{
    public uint MyInternalErrorCode { get; set; }

    public MyOwnException(uint errorCode)
    {
        MyInternalErrorCode = errorCode;
    }

    /// <inheritdoc />
    public MyOwnException(string? message) : base(message)
    {
    }

    public MyOwnException(string? message, uint myInternalErrorCode) : base(message)
    {
        MyInternalErrorCode = myInternalErrorCode;
    }

    /// <inheritdoc />
    public MyOwnException(string? message, Exception? innerException) : base(message, innerException)
    {
    }

    public MyOwnException(string? message, Exception? innerException, uint myInternalErrorCode) : base(message, innerException)
    {
        MyInternalErrorCode = myInternalErrorCode;
    }
}

Catching multiple exceptions

Please refer to my article about when

Catching unhandled exceptions

To catch all unhandled exceptions in your program, e. g. for logging it to a file instead of default logging facilities it is possible to subscribe to some even:

static async Task Main(string[] args)
{
    // subscribe to event for all unhandled eceptions
    AppDomain.CurrentDomain.UnhandledException += ApplicationUnhandledException;
    // rest of code...
}

// event handler
private static void ApplicationUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    // log the exception for example
    Logger.Fatal((Exception) e.ExceptionObject, "Unhandled exception: {0}", e.ExceptionObject);
}

Using Tasks the above will not work, but the TaskScheduler class does provide an Event UnobservedTaskException which we can use in this case.

Credits

Photo by Anthony Duran on Unsplash