You are on page 1of 17

Exception Handling in C#

Author: Wim UYTTERSPROT, wim@u2u.be

Introduction
In C#, we have a built-in support for exception handling at our disposal, which is used for exceptions to the usual instruction route. The key to understand the concept of an exception and of the exception handling, is to not consider an exception as a fatal error, but as a deviant condition to which should be reacted. Exceptions should be handled in a try-catch block or a try-catch-finally block. Furthermore, an exception can be caused explicitly by means of the throw statement.

.NET Exceptions
The exception handling mechanism is not only to be found in the C# language, but also in the .NET Common Language Runtime: each method of the .NET Framework is thus conceived that it throws an exception as soon as an error or an anomaly occurs. Consequently, being able to treat exceptions is an essential skill for each .NET programmer, no matter which language he/she uses. When an exception is thrown, an exception object is passed on to the call-stack* until an exception handler is found. If an exception handler is found, the program is further executed as from the exception handler that handled the exception. If no exception handler is found on the call stack, the .NET Common Language Runtime stops the process in which the exception has been thrown, and the runtime shows the name, the message string and stack trace of the exception. It is each .NET programmers responsibility to catch all exceptions so that his/her program doesnt suddenly crash. *The call stack is a list of functions that have been called. If, for example, the Main function calls the function Fa, which in its turn calls the function Fb, which calls Fc, then Main, Fa, Fb and Fc are to be found in that order on the call stack. The .NET exception mechanism is offered in both C# and VB.NET and largely corresponds to that of JAVA or that of C++. VB6 programmers only know error trapping, which is much less powerful.

The try-catch block


Lets start with a classic example: the integer division by zero (notice the backslash):
int z = 0; int i = 1/z;

When we execute this code, we get the following output, after which the execution of the code is abruptly stopped:
Unhandled Exception: System.DivideByZeroException/ Attempted to divide by zero. at ...

If we want to intercept this exception in our code, we will have to make use of Exception handling. For this purpose we use a try-catch block:

try-catch block
try { int z=0; int i = 1/z; } catch { Console.WriteLine("Exception handled: Division by zero"); }

As a result, the exception is handled and the process isnt stopped abruptly anymore; quite the contrary: the execution of the code continues after the catch statement.

The Exception object The Exception base class


If we want to get more information about an exception, we can define an exception object as argument in the catch statement. This exception object has to be of type System.Exception (as in the following example) or from a derived class:
try {

int z = 0; int i = 1/z; } catch (Exception e) { Console.WriteLine(e.Message); }

The Message property of the Exception class can be questioned to get to know the reason of the exception. The example above contains e.Message:
Attempted to divide by zero.

For the Exception object, we can also make use of a derivative of an Exception class, e.g. the System.DivideByZeroException:
try { int z = 0; int i = 1/z; } catch (DivideByZeroException e) { Console.WriteLine(e.Message); }

For your information: The DivideByZeroException class is derived from the ArithmeticException, which is in its turn derived from the SystemException, which is in its turn derived from Exception.

Derived Exception classes


Lets have a look at another classic example, namely the IndexOutOfRangeException:
int[] a = new int[5]; a[7] = 10;

When we execute this code, we get the following output, after which the execution of the code stops abruptly:
Unhandled Exception: System.IndexOutOfRangeException: An exception of type System.IndexOutOfRangeException was thrown. at ...

In order to catch this exception, we can immediately make use of a try-catch block with as argument an IndexOutOfRangeException object:
int[] a = new int[5]; try { a[7] = 10; } catch (IndexOutOfRangeException e) { Console.WriteLine("Exception handled: " + e.Message); }

Exceptions in functions
Usually, the exception handling mechanism is used to catch exceptions that are caused in functions. When an exception is caused in a function, the runtime first looks for an exception handler in that function itself. If the runtime doesnt find one there, it looks for an exception handler in the code that has called the function. Then there are two possibilities: In the code calling the function, the runtime find or doesnt find an exception handler:

There is an exception handler: Then the exception handler deals with the exception, whereupon the instruction, immediately following the try-catch block, is executed. There is no exception handler: The runtime then jumps to a higher function in the calling stack with the intention of finding an exception handler there. If the runtime cant find an exception handler anywhere in the calling stack, then the runtime itself handles the exception by abruptly stopping the execution of the program.

First example
Lets have a look at the Toons collection class in the following example:
public class Toons { private Toon[] toons; public Toons(int n)

{ toons = new Toon[n]; } public void SetAt(int index, Toon toon) { toons[index] = toon; } public Toon GetAt(int index) { return toons[index]; } }

At first sight, there is nothing wrong with this class definition. But now give the following testcode a try-out; it presumes that barney, betty and bambam are references to instantiated Toon objects:
public static int Main(string[] args) { ... Toons neighbours = new Toons(3); neighbours.SetAt(0, barney); neighbours.SetAt(1, betty); neighbours.SetAt(2, bambam); ... neighbours.GetAt(5).Draw(); // line 50 ... }

During the execution of the GetAt(5) call, an exception of type IndexOutOfRangeException is caused in the GetAt function. Since the GetAt function itself doesnt catch the exception, the exception is sent on to the context that has called this GetAt function; in this case the Main function on line 50. As this line is not part of a try-catch block, the runtime itself will have to catch the exception and it will stop the program abruptly saying:
Unhandled Exception: System.IndexOutOfRangeException: An exception of type System.IndexOutOfRangeException was thrown. at ToonTown.Toons.GetAt(Int32 index) in (...) at ToonTown.Cartoon.Main(String[] args) in (...): line 50

If we want to catch this exception in the Main function, then we write for example:
try { neighbours.GetAt(5).Zoom(12.0); } catch (IndexOutOfRangeException)

{ //... }

If we want, on the other hand, to catch the exception in the GetAt function, then it can be defined, for example, as follows:
public Toon GetAt(int index) { try { return toons[index]; } catch (IndexOutOfRangeException) { return null; } }

In our example, this solution is not preferable. Despite the fact that the IndexOutOfRangeException has been intercepted in GetAt(5), a new exception occurs, this time of type NullReferenceException. While catching the IndexOutOfRangeException in GetAt(5), Nothing is returned to serve as a reference to call the Draw() function with.

Second example
In the second example we try to convert a string variable into a decimal by means of the Convert.ToDecimal function. But this instruction can easily go wrong, for example, when the string is not well-formed and as a consequence not convertible to a decimal value. If the conversion is unsuccessful, the ToDecimal function will throw a FormatException object, as we can read in the C# documentation of the function ToDecimal. This exception should be caught on the spot where the ToDecimal is called:
string s = "1B"; decimal d; try { d = s.ToDecimal(); } catch { }

Multiple exception handlers


If we want to take several types of exceptions into account, then its best to make use of a multiple exception handler block, this is one block with several immediately successive catch statements belonging to one single try statement. We illustrate this in the following example in which 3 kinds of exceptions can be thrown. Notice that only one single try has been defined, with in addition 3 different catch statements with each time an argument of another type.
string[] textTarget; // code before try block try { textTarget = new string[n]; for (int i=0; i<n; i++) { textTarget[i] = textSource[i]; } Console.WriteLine("At end of try block"); } catch (NullReferenceException e) { Console.WriteLine(e.Message + ": textSource is null"); } catch (IndexOutOfRangeException e) { Console.WriteLine(e.Message + ": textSource.Length is less than n"); } catch (OutOfMemoryException e) { Console.WriteLine(e.Message + ": n has negative value"); } Console.WriteLine("After try-catch block"); This code tries to copy textSource as an array of strings to textTarget.

First situation
In our first situation, we look at the case in which the variables textSource and n have usual values, for example:
string[] textSource = {"Welcome ", "to ", "ToonTown "}; int n = 3;

In this way, the execution of the code passes off smoothly, and we get the following output:
At end of try block After try-catch block

Second situation
As second situation, we look at the case in which the reference textSource equals nothing, for instance:
string[] textSource = null; int n = 3;

This makes the execution of the code go wrong as soon as the first element is called. The caused NullReferenceException is caught by the first catch statement. We get the following output:
The value nothing was found where an instance of an object was required.: textSource is nothing After try-catch block

Third situation
Next, we test the situation in which n, for example, equals 4, so it is bigger than the amount of available elements in the array:
string[] textSource = {"Welcome ", "to ", "ToonTown "}; int n = 4;

As a result, the execution of the code goes wrong as soon as the index 3 is used to call the 4th element in the textSource array. The caused IndexOutOfRangeException is caught by the second catch statement. And we get following output:
An exception of type System.IndexOutOfRangeException was thrown.: textSource.Length is less than n After try-catch block

Last situation
The last one on the list is the situation in which n is, for example, negative, lets say -1:
string[] textSource = {"Welcome ", "to ", "ToonTown "}; int n = -1;

This makes the execution of the code go wrong in the allocation for textTarget. This is the output we get:
An exception of type System.OutOfMemoryException was thrown.: n has negative value After try-catch block

Order of the catch statements


When drawing up an exception handling block, you always have to keep in mind which order you put the catch statements in. For when an exception occurs, the catch statements are always called in that order. For exceptions between which an inheritance relation exists, this order is also checked by the C# compiler. The compiler, for instance, doesnt accept that we try to catch a more general exception before the derived exception. If this were permitted, the general exception catch would catch all exceptions. The following example shows that the order of the catch statements is important: as IndexOutOfRangeException is a subclass of Exception, the subclass catch statement (= the second catch) can never be reached here, which doesnt make sense.
int[] a = new int[5]; try { a[7] = 10; } catch (Exception e) { Console.WriteLine("Exception handled: " + e.Message); } catch (IndexOutOfRangeException e) // compiler error { Console.WriteLine("Exception handled: " + e.Message); }

The finally block


When a program reserves resources, it is important that the reserved resources are always released after being used. This applies to both situations: when everything goes smoothly, and when something goes wrong and an exception is thrown. (Reserving resources implies for example: opening a file, opening a connection, starting a process,

using a switch,...) To solve this kind of problems easily, C# provides a powerful instrument: the finally-statement within a try-(catch)-finally block. Take the simple example of a switch being turned on. The success or otherwise of the operations that follow on the turning on of the switch doesnt matter: the switch needs to be turned off again at the end. In the following exemplary code, this is realized by putting the turning off of the switch in a finally-block.
try { flag = true; Console.WriteLine("In try-block: flag is " + flag); Console.WriteLine("Do something wild"); string wild = null; wild.Trim(); // throws exception. Comment this instruction. } finally { flag = false; Console.WriteLine("In finally-block: flag is " + flag); } Console.WriteLine("After try-finally block: flag is " + flag);

In this block, the instruction wild.Trim() throws an exception of type NullReferenceException. This exception is not caught here so the execution of this example is abruptly stopped. However, the finally-block is still executed and the flag is reset in its original condition. This example gives the following output:
In try-block: flag is True Do something wild Exception occurred: NullReferenceException: (...) at System.String.Trim() In finally-block: flag is False

Mostly, a finally statement is combined with one or more catch statements. For example:
try { flag = true; Console.WriteLine("In try-block: flag is " + flag); Console.WriteLine("Do something wild"); string wild = null; wild.Trim(); // throws exception. Comment this instruction. } catch (Exception e) { Console.WriteLine("Exception catched"); } finally { flag = false; Console.WriteLine("In finally-block: flag is " + flag);

} Console.WriteLine("After try-finally block: flag is " + flag);

Now the exception is dealt with first, and then the finally-block is executed. This time, the output is:
In try-block: flag is True do something wild Exception catched. In finally-block: flag is False After try-finally block: flag is False

Remark: the order try-catch-(catch)-finally is obligatory. In C#, it is not possible to place the finally-block in front of the catch-block.

Throwing exceptions
The exception mechanism allows us to cause our exceptions ourselves by using the throw statement. In .NET, only objects of type Exception or of derived types can be thrown. In JAVA, exceptions also have to be of type Exception or derived type; moreover, in JAVA there is also the Throwable class, which is the base class of the Exception and the Error class. In oplocation to VB.NET, C# and so also to JAVA, in C++ an exception can be of any type.

Simple example
Lets have a look at the following example. If the input string is too long, an Exception object will be instantiated via the Exception constructor which we provide with the message of the exception as argument. Next, this exception object is thrown by means of the throw statement.
string s = Console.In.ReadLine(); if (s.Length > 20) { throw new Exception("Input string is too long"); }

Test this code by means of a string that contains more than 20 characters. The output is then for example:
Welcome to the United ToonTowns Unhandled Exception: System.Exception: input string is too long at (...)

It is obvious that throwing exceptions is also possible via a reference of type Exception:
Exception e; e = new Exception("input string is too long"); throw e;

We repeat again that an Exception object needs to be thrown, with the emphasis on object. Although the compiler accepts the following code, in runtime we cause a NullReferenceException because a reference equal to nothing is thrown:
Exception e = null; throw e;

Creating your own Exception class


In .NET and consequently in C#, an exception has to be an object of type Exception or derived from it. In other words, this means that we can define our own exception classes by deriving them from Exception. In the example of our Toon class, we have, for instance, the Zoom function in which we only let the scale of a Toon object adopt a value within the interval of 0 up to 500%. We now want to adjust the Zoom function in such a way that it throws an exception each time the value exceeds the interval.

Subclassing the Exception-class


For that purpose we first define an InvalidScaleException class:
public class InvalideScaleException : Exception { private double invalidscale; public InvalideScaleException(double invalidscale) { this.invalidscale = invalidscale; }

public override string ToString() { return "Invalid scale with value " + invalidscale; } }

We can simplify the definition of this class if we dont want to make use of the invalidscale member:
public class InvalideScaleException : Exception { public InvalideScaleException(double invalidscale) : base("Invalid scale with value " + invalidscale) {} }

Notice that the invalidscale parameter in string format in the definition above is passed on to the constructor of the base class (this is Exception). Now, we throw an InvalideScaleException object in the Zoom function when the scale value goes beyond the accepted values:
public void Zoom (double ratio) { double oldScale = Scale; Scale *= ratio; if (oldScale != Scale) { Draw(); } else { throw new InvalideScaleException(scale*ratio); } }

This InvalideScaleException object is caught on the place where we call the Zoom function:
Toon fred = new Toon( null, "Fred Flintstone", "fred.wmf", 100, 200, 1.0); try { fred.Scale = .75; fred.Zoom(7.0); // throws InvalideScaleException fred.Move(102, 202); } catch (InvalideScaleException e) { Console.WriteLine(e.Message);

This logically results in:


Invalid scale with value 5.25

We go one step further: in case of an incorrect value, we now throw the InvalideScaleException object from the setter of the Scale property of the Toon class derived from the Shape class:
public class Toon : Shape { ... public double Scale { override set { if (value>0.0 && value<=5.0) { scale = value; } else { throw new InvalideScaleException(value); } } } ... }

As a result, we dont have to throw an exception anymore in the definition of the Shape class (see below), and the definition of the Zoom function becomes extremely simple. But dont take it for granted that this simple Zoom function of the Shape class wont be able to throw an exception anymore, for this can now occur from the Scale setter in the represented Toon class (see above).

public class Shape : IScalable { ... public virtual double Scale { get { return scale; } set { scale = value; } } public double scale; public void Zoom (double ratio) { Scale *= ratio; // override in Toon class can throw an exception Draw(); } }

We verify again what happens when we call the Zoom function (as we did above):
fred.Scale = .75 fred.Zoom(7.0) throws InvalideScaleException

The Zoom function of the Shape class then calls the Scale setter of the Toon class (because the Scale setter of the Shape class is overridden in the Toon class). In the Scale setter, the Exception object is trown:
Unhandled Exception occurred: ToonTown.InvalideScaleException: Invalid scale with value 5.25 at ToonTown.Toon.set_Scale(ByVal value As Double) in (...) at ToonTown.Shape.Zoom(ByVal ratio As Double) in (...) at ToonTown.CarToon.Main() in (...)

Hierarchy of the own Exception classes


It is often useful to structure ones own exceptions hierarchically. Look for instance at the following example: the ShapeException has been defined as the base class for the derived InvalidScaleException and the InvalidLocationException classes.
public class ShapeException : Exception { public ShapeException(string message) : base(message) { } } public class InvalideScaleException : ShapeException { public InvalideScaleException(double invalidscale) : base("Invalid scale with value " + invalidscale) { } } public class InvalideLocationException : ShapeException { public InvalideLocationException(Point invalidpoint) : base("Invalid location with value " + invalidpoint) { } }

A hierarchy of own exception classes allows us to distinguish in great detail between the different kinds of exceptions (of derived type), by means of a multiple exception handlers block:
Toon fred; try { // ... } catch (InvalideScaleException e) { // ... } catch (InvalideLocationException e) { // ... }

If there is no need for a detailed distinction, a simple catch statement can be used to catch exceptions of the base type, and consequently also the exceptions of the derived

types. In the following example, not only the exception objects of types ShapeException are caught, but also the types derived from it, namely InvalideScaleException and InvalideLocationException, and this with only one single catch statement:
Toon fred; try { fred = new Toon( null, "Fred Flintstone", "fred.wmf", 100, 200, 1.0); fred.Scale = 7.5 fred.Move(-1, 100); } catch (ShapeException e) { // catches also InvalideScaleException and InvalideLocationException Console.WriteLine(e.Message); }

You might also like