Page 3 of 5
To raise an exception all you have to do is define a custom exception type or use one of the existing types and simply use throw exception type.
throw new NullReferenceException();
You can also use throw within a catch block to pass the exception on to a higher level handler - if there is one. It is always worth being clear that throwing an exception from within a handler means that you are giving up on the exception and allowing some other part of the system deal with it. The possible consequence of this is that it isn't handled and a runtime error occurs.
catch (DivideByZeroException myException)
"division by zero isn't allowed " +
passes the exception on to some other handler.
Of course if you want to throw a completely customised exception you need to create your own type that derives from another exception class. You also have to do the work in constructing an object of the type. It's accepted practice to end all exception classes with Exception so, for example, if you wanted to raise a custom exception "TooLongException", in case a task is taking too long you would define something like:
class TooLongException : Exception
public TooLongException(string message,
Exceptions usually have three constructors but you don't have to follow this rule. The default constructor simply returns a new object of the type and allows the exception to be raised simply as:
throw new TooLongException();
The second constructor allows a message to be included when the exception is raised:
throw new TooLongException(
"much much too long");
and finally the third constructor that allows a thrown exception to be passed on as part of the exception:
throw new TooLongException(
"much much too long", innercause);
Of course in a real example the inner exception would have been generated elsewhere and passed up to the catch handler that is throwing the TooLong exception. This allows the next handler to determine why the TooLong exception might have occurred.
Considering the building of a custom exception brings us to the subject of what information should be packaged into an exception object.
There are some standard properties that are inherited from Exception but you can add as many extras as seem appropriate. The most commonly used are:
- the message property to pass on an error message to the user
- Helplink which is the URL of a helpfile
- InnerException which stores any exception passed to the exception
- Source and TargetSite which give the object and function that caused the exception.
More complicated is the HResult property which is used to return the standard Windows error code if the exception was caused by an API.
The most complicated piece of information that an exception object contains is the stack trace - a string containing a list of what method called what to get you to the location where the exception occurred. You can add to the properties and methods of the exception class but most programmers don't and there are some good reasons why not.
The state problem
Mention of the stack trace brings us to the central problem of exception handling.
Exceptions in C# and Windows in general are "structured" in the sense that they are nested according to the call stack. If a method raises an exception and doesn't have an exception handler then the system looks back through the call stack to find the first method up the chain that does. This is perfectly reasonable behaviour and in fact without out it exception handling would be a waste of time.
For example, suppose you write a try block:
and a set of carefully constructed catch blocks that handle every possible exception. Now suppose that "do things" makes method calls. If any exception that occurred within a method that didn't handle it wasn't passed up the call stack then our efforts at comprehensive exception handling would be nonsense - the program could still crash with a runtime error within the try block.
However exception handling has some deep problems if you are planning to allow the program to continue after an exception.
In practice most programmers simply use exception handling as a way of allowing the application to make a soft landing rather than crash. It saves face rather than being useful. Typically they provide a more informative, or more friendly, error message that tells the user who to contact and what information to provide. Of course this is all Windows dressing because if the exception really is an exception and not an error state that the programmers were too lazy to detect then there will be nothing that can be done to correct it - other than improve or fix the hardware.
Suppose, however, that you are trying to use exceptions to allow an application to continue. This is a much more difficult problem.
The first idea you need to accept is exception safe code.
If the code in the try block raises an exception then you have to ask what side effects are there when you reach the catch block. Side effects are the change in state that the try block has implemented up to the point that it raised the exception. For example, if the try block opened a file then it is still open. Side effects include deeper problems such as memory leaks and orphaned resources in general.
Notice that the try block has its own scope so if you stick to the rule that the code in a try block will not access anything not created in the block it is almost (but not) guaranteed to be exception safe.
Notice also that the very act of propagating the exception up the call stack of necessity unwinds the state back to the method that handles the exception.
That is, if you have a catch block that is triggered by an exception thrown by a method called within the try block then all trace of the internal state of that method has gone. This doesn't make cleaning up after the method an attractive proposition. Basically if your aim it to continue the application you need to handle exceptions at the lowest level and avoid unwinding the call stack - which sort of makes the whole idea of structured exception handling a bit of a nonesense.