Saturday 5 September 2015

Exception handling

Writing defensive code is the pro-active effort of preventing exceptions, unfortunately not all exceptions are preventable, not all of them are fatal and often times they are in fact appropriate; regardless if exceptions are good or bad, they should always be handled with grace. The user experience is key, if your application crashes for any reason the odds of it being uninstalled increase exponentially.

You may wonder how do we handle exceptions? The answer is exception handling, which is implemented using try-catch blocks. The try block contains the code that may throw an exception, and the catch block contains the code that will handle the exception if it is thrown. The catch block is executed only if an exception is thrown in the try block.


namespace pav.exceptionHandling;
class Program
{
    static void Main(string[] args)
    {
        var str = "1d23";

        try
        {
            var i = int.Parse(str);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType() + ":" + ex.Message);
        }
    }
}


The above is a very simple example which catches our format exception, however you may notice that we are actually catching our base exception. The exception class is a catch all exception, it is the base exception of all exceptions,  It is best practice to catch your exceptions as specifically as possible


namespace pav.exceptionHandling;
class Program
{
    static void Main(string[] args)
    {
        var str = "1d23";

        try
        {
            var i = int.Parse(str);
        }
        catch (FormatException ex)
        {
            Console.WriteLine("format exctiption " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType() + ":" + ex.Message);
        }
    }
}


We left the (Exception ex) at the end to ensure that we catch anything that slipped through our exception chain. In this simple example we know the exception which will occur in our try block, however we may have for more complex code to test, which could through a number of different exceptions, each of which may need to be handled in a different way or at the very least provide exception specific information to the user or log.

We can also use the finally block, which is executed after the try block and all of its catch blocks, regardless of whether an exception was thrown or not. this is ideal in situations where you have to open some sort of stream in your try but an exception is thrown before you have a chance to close the stream, without the finally block you would create a memory leak which over time would crash your program.


namespace pav.exceptionHandling;
class Program
{
    static void Main(string[] args)
    {
        var str = "1d23";

        try
        {
            var i = int.Parse(str);
        }
        catch (FormatException ex)
        {
            Console.WriteLine("format exctiption " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType() + ":" + ex.Message);
        }
        finally
        {
            Console.WriteLine("Always print this");
        }
    }
}


In the above each catch block will only fire if the corresponding exception occurs inside our try block, however the finally block will always fire, exception or not.

It is possible to nest try-catch blocks, in nested try-catch blocks if an exception is thrown the innermost catch block will first try to handle the exception. however if the innermost catch block does not handle the exception, the next outer catch block is attempts to, and so on, until a catch block that can handle the exception is found. If no catch block can handle the exception, the exception propagates up the call stack until it is caught by a catch block in an outer try-catch block or until it is not caught and the program terminates.


namespace pav.exceptionHandling;

class Program
{
    static void Main(string[] args)
    {
        var str = "1d23";

        try
        {
            try
            {
                var i = int.Parse(str);
            }
            catch (FormatException ex)
            {
                throw;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType() + ":" + ex.Message);
        }
        finally
        {
            Console.WriteLine("Always print this");
        }
    }
}

Keep in mind that from a code readability angle, it's generally bad practice to use nested try-catch blocks, remember your goal is to write code that is efficient and simple.