BlackWasp
C# Programming
.NET 1.1

Throwing Exceptions in C#

The thirty-fifth part of the C# Fundamentals tutorial completes an investigation of exception handling. In this article we will consider the throwing of exceptions to report error conditions.  This includes the use of standard and custom exception types.

Why Throw Exceptions?

In the previous part of the C# Fundamentals tutorial, I introduced exception handling and the facility to catch exceptions for logging purposes, graceful recovery or other activities.  This was achieved using the try / catch / finally block provided by the C# programming language.

During normal processing, it is possible for an error condition to be detected.  In older languages the method or subroutine would be exited early and a return code would be used to indicate the error status.  When developing software for the .NET framework, this method is possible but does not provide all of the flexibility of exception handling that is provided by C#.  It is preferable, therefore, to raise or throw exceptions explicitly when error conditions occurs and allow exceptions to be captured by the next available try / catch / finally block or by the C# runtime system.

It is important that exceptions are thrown only when an unexpected or invalid activity occurs that prevents a method from completing its normal function.  Exception handling introduces a small overhead and lowers performance so should not be used for normal program flow instead of conditional processing.  It can also be difficult to maintain code that misuses exception handling in this way.

Good uses of exceptions include:

  • throwing an exception when an invalid parameter is passed to a method.  The ArgumentException or one of its derived exception classes should be thrown in this situation.
  • throwing an exception when a call is made to a method that cannot operate because other information must be initialised or other methods must be called beforehand.  An InvalidOperationException could be thrown in this case.

Throwing an Exception

When an error condition is encountered, the throw command is used to raise an exception.  The throw command's syntax is as follows:

throw exception;

The exception is an exception object containing the details of the exception to be raised.  This can be declared as an object and initialised before the throw command.  However, it is more usual to create a new exception object within the throw statement, using the new keyword and one of the exception's constructors to set the object's properties.

The following example uses a console application that requires at least one start-up parameter in order to operate.  If no start-up parameter is provided, an exception of type ArgumentException is thrown.  The constructor used in the example requires a single string parameter containing the error message for the exception.

using System;

namespace BlackWasp
{
    class TestApp
    {
        static void Main(string[] args)
        {
            // Check that a parameter was provided
            if (args.Length == 0)
            {
                throw new ArgumentException("A start-up parameter is required.");
            }

            Console.WriteLine("{0} argument(s) provided", args.Length);
        }
    }
}

When executed correctly with a parameter, the above program runs without error and outputs the number of parameters detected.  However, if the number of arguments used is zero, this is identified by the if statement and an exception is thrown.  This avoids unexpected exceptions occurring later due to the parameters being invalid.

NB: The class of exception object to throw should be appropriate for the error condition that has occurred.  Each exception object has its own set of constructors that may differ from that shown in the above example.  For details of other exception classes provided by the .NET Framework, visit the System Exceptions Hierarchy page of Microsoft's MSDN web site.

Re-Throwing Exceptions

When an exception is caught in a catch block, the exception is considered to have been processed and code execution continues as normal.  In some situations it is useful to catch the exception but still have it thrown to be caught again.  For example, a method may catch all exceptions so that they can be logged and then re-throw the exception to be handled appropriately by the calling function.

When an exception is thrown explicitly using the syntax previously discussed, a new exception object is constructed.  This exception object contains only the basic information set by the programmer; information such as the StackTrace property of the original exception is lost.  To re-throw the exception and retain this additional information, the throw command is used without specifying an exception object.  This is achieved using the following syntax:

throw;

The following example code demonstrates how this syntax can be used.  For simplicity, the methods called are not defined so this code cannot be directly executed.

static void Main(string[] args)
{
    try
    {
        InitialiseData(args[0]);
        SaveToDisk();
    }
    catch (Exception ex)
    {
        // Log the details of any exception and re-throw
        LogException();
        throw;        
    }
}

Using the InnerException Property

In the previous article in the C# Fundamentals tutorial, the InnerException property of an exception was discussed.  This property can be used to hold the details of an initial exception that caused a further exception to be thrown.  This mechanism is useful when you wish to throw one exception in response to another, but without losing the properties of the original exception.

The following example extends the re-throw sample above by throwing a file not found exception.  The file not found exception's constructor is used to set a new error message and to store the caught exception in the InnerException property.

static void Main(string[] args)
{
    try
    {
        InitialiseData(args[0]);
        SaveToDisk();
    }
    catch (Exception ex)
    {
        // Log the details of any exception and re-throw
        LogException();
        throw new System.IO.FileNotFoundException("Invalid file argument", ex);
    }
}

NB: The above code is provided only as an example of a method by which the InnerException property can be set.  It is not good practise to use a catch-all and throw a new exception as this can mask serious system problems.

Custom Exceptions

The .NET Framework provides a rich set of system-defined exception types that can be thrown and caught by the C# developer.  However, the list of available exceptions does not cover every eventuality and often it is more appropriate to define custom exceptions for specific error scenarios.  This can be achieved by deriving a new exception class from any of the existing types, usually the ApplicationException class.

In the final section of this article we will define a new exception class and demonstrate how it may be thrown and handled.  This will be a simple exception with no custom methods or properties.  These can be added to the derived class using standard object-oriented programming techniques.  However, this is beyond the scope of the C# Fundamentals tutorial and will instead be described in a future object-oriented programming tutorial.

Defining the Custom Exception

The custom exception that we will create will be used to report an exception when attempting to print a page with margins that are too small for the selected printer.  To follow the standard naming of exceptions the new class will be named InvalidPrinterMarginsException.  To define the new class within the current namespace and indicate that it is derived from ApplicationException, the following code is used:

class InvalidPrinterMarginsException : ApplicationException
{

}

The ApplicationException class provides three basic constructors.  The first requires no parameters and creates an exception with no properties set.  The second accepts a string parameter containing the error message to hold in the exception object.  The final constructor allows a message and an inner exception object to be provided during initialisation.  These three constructors are not automatically inherited by the new exception type so must be described within the class as follows:

class InvalidPrinterMarginsException : ApplicationException
{
    // Use the default ApplicationException constructors
    public InvalidPrinterMarginsException() : base() {}
    public InvalidPrinterMarginsException(string s) : base(s) {}
    public InvalidPrinterMarginsException(string s, Exception ex) : base(s, ex) {}
}

Throwing and Catching the Custom Exception

Once the custom exception is created, it may be thrown and caught in the same way as any other exception.  This includes catching the exact exception or the more generic types that it is derived from.  Indeed, one custom exception may derive from another to create a full hierarchy of application exceptions for flexible handling.

The final code sample combines the custom exception with the code for a simple console application.  This program throws the custom exception within a try block.  The exception message is outputted within the following catch block.

using System;

namespace BlackWasp
{
    class TestApp
    {
        static void Main(string[] args)
        {
            try
            {
                // Throw a test exception
                throw new InvalidPrinterMarginsException
                    ("The margins are too small");
            }
            catch (InvalidPrinterMarginsException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

    // Custom exception class
    class InvalidPrinterMarginsException : ApplicationException
    {
        // Use the default ApplicationException constructors
        public InvalidPrinterMarginsException() : base() {}
        public InvalidPrinterMarginsException(string s) : base(s) {}
        public InvalidPrinterMarginsException(string s, Exception ex)
            : base(s, ex) {}
    }
}

A Final Note on ApplicationException

When Microsoft created the .NET framework they defined two base classes for system-defined exceptions (SystemException) and for custom exceptions (ApplicationException).  However, on reviewing this segregation, Microsoft realised that the benefits that they had expected from the structure were not as expected.  For this reason, Microsoft now advises developers to derive custom exceptions directly from the Exception class.  This is to keep the hierarchy of exceptions flatter.  However, the ApplicationException remains a part of the .NET framework for backwards compatibility at the time of writing.

Link to this Page9 April 2007
RSS RSS Feed
76 users on-line