ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Learning the C# Error Handling Mechanism

by Budi Kurniawan
09/04/2001

Error handling is an important feature of a programming language. A good error handling mechanism will make it easier for the programmers of that language to write robust applications. This article introduces you to error handling in C# and offers examples on how to use it.

Most older programming languages, such as C and Basic, rely on the heavy use of if statements to detect if an error has occurred. As programs become bigger and more complicated, this approach to that kind of error handling creates more and more insomniacs in the computer programmer profession. Creating robust and reliable large applications is also exponentially more difficult as the number of lines of code increases. More modern programming languages, such as C++, Java, C# and VB.NET, base their error-handling strategy on code isolation. Part of the code that could potentially lead to an error is isolated in a block, and should an error occur, this error is caught and handled locally. This approach seems to work satisfactorily. No more if statement to check the returned value of a function, no more branching that can turn your code into a spaghetti mess.

C# follows Java's and C++'s approach to error handling: throwing exceptions on errors. In C#, to trap an error is to catch it. You use a try ... catch ... finally block to handle errors. You isolate code that could lead to an error in the try clause, and when the error does occur, program control is passed to the code in the catch clause. The optional finally clause will be executed regardless if there was an error or not. The syntax of the try ... catch ... finally block is as follows.

try {
  // code that could lead to an error
}
catch (Exception Type [ variable ]) {
  // code that needs to be executed when an error occurs
}
finally {
  // code that needs to run whether or not an 
  // error has occurred.
}

Note that, unlike in Java, the exception object variable in the catch block is optional.

.NET Exception Classes

Related Reading

C# EssentialsC# Essentials
By Ben Albahari, Peter Drayton & Brad Merrill
Table of Contents
Index
Sample Chapter
Full Description
Read Online -- Safari

C# is part of the Microsoft .NET Framework. C# does not have a type library of its own, but shares the .NET Framework class library with other .NET languages. The .NET class library provides a root class for exception handling: the Exception class in the System namespace. This class is the parent class of all exception classes.

The Exception class has a number of useful properties and methods. For example, its Message property gives you the error message text that you can display on the screen so that your user can report that back to you. Another property, Source, gets or sets a string containing the name of the application or the object that causes the error.

The Exception class has three methods of its own. They are:

The code in Listing 1 illustrates C# error handling in a class named Testing. The Main method of the class has a try ... catch block that will catch any exception that occurs. Consider the for loop in the try clause:

for (int i=5; i>=0; i--) {
  int b = 2/i;
}

The last iteration will have i=0, and a division by zero will occur. What happens then?


Listing 1: A simple exception handling block

using System;
class Testing {
  public static void Main() {
    try {
      for (int i=5; i>=0; i--) {
        int b = 2/i;
      }
    }
    catch (Exception e) {
      Console.WriteLine( e.ToString() );
    }
  }
}

Because the code is placed inside of a try ... catch block, the error won't cause the program to crash. The exception will be caught and control will be passed to the code in the catch clause. The user will see the following in the console:

System.DivideByZeroException: Attempted to divide by zero.

Practically, you can catch all exceptions using Exception in the catch clause. However, when catching an exception, often you want to be more specific, in which case you can then use derivatives of Exception, which we will see in the later section of this article.

Throwing an Exception From a Method

When catching an exception in a method, you have two options in regard to handling the error that occurs inside the method. You can either handle it in the method, and thus quietly catch the exception without notifying the caller, or you can throw the exception back to the caller and let the caller handle it. If you choose the second option, the calling code must catch the exception that is thrown back by the method.

For example, let's say you have a method called GetFileStream, to which you can pass a filepath, which is the path to the file you want to open. The GetFileStream method will try to open the file for you and return the FileStream object of the file. If the file is not found, however, it will throw a FileNotFoundException object, and this exception must be caught by the caller of the GetFileStream function. The code is given in Listing 2.


Listing 2: Throwing back an exception from a method

using System;
using System.IO;

class Testing {

  public FileStream GetFileStream(String filePath) {
    try {
      FileStream fs = File.Open(filePath, FileMode.Open);
      return fs;
    }
    catch (FileNotFoundException e) {
      throw e;
    }
  }

  public static void Main(String[] args) {
    Testing t = new Testing();
    try {
      t.GetFileStream(args[0]);
      Console.WriteLine("Successful");
    }
    catch (FileNotFoundException) {
      Console.WriteLine("File Not Found");
    }
  }
}

After you compile the code, you can run it by typing the program name followed by the path to a file you want to open. For example, this will pass the CompanySecret.txt file on the C drive.

Testing C:\CompanySecret.txt
If the file is found and can be opened, the user will see the "Successful" string on the console. Otherwise, a "File Not Found" error message will be printed.

If you are a Java programmer, note that C# does not have the throws keyword that you normally use in Java to tell the compiler that an exception might be thrown from your method.

Exception Catching Order

Sometimes there can be more than one type of exception that can occur in a try clause. You can catch all of them if you use Exception in the catch clause of your try ... catch block. However, there are cases where you want your code to react differently on different types of exceptions. If this is the case, you then need to provide a catch clause for every exception type that could be thrown. Your code will then look like the following:

try {
// code that could thrown an exception
}
catch (ExceptionType_1 e1) {
  // code that must be run when ExceptionType_1 occurs
}
catch (ExceptionType_2 e2) {
  // code that must be run when ExceptionType_2 occurs
}
.
.
.
catch (ExceptionType_n en) {
  // code that must be run when ExceptionType_n occurs
}

When an exception occurs, the exception is passed up the stack and each catch block is given the opportunity to handle the exception. The order of catch statements is important. You should put catch blocks targeted to specific exceptions before a general exception catch block, or the compiler will issue an error. The proper catch block is determined by matching the type of the exception to the name of the exception specified in the catch block. If there is no specific catch block, then the exception is caught by a general catch block, if one exists. Because sometimes it is very hard to predict all exceptions that can be thrown in all occasions, it is normal practice to use Exception as the type of the last catch clause, like in the following:

try {
// code that could thrown an exception
}
catch (ExceptionType_1 e1) {
  // code that must be run when ExceptionType_1 occurs
}
catch (ExceptionType_2 e2) {
  // code that must be run when ExceptionType_2 occurs
}
.
.
.
catch (ExceptionType_n en) {
  // code that must be run when ExceptionType_n occurs
}

catch (Exception e) {
  // code that must be run when an exception other 
  // than ExceptionType_1 to ExceptionType_n occurs
}

The code in Listing 2 only catches a FileNotFoundException. However, there are other situations where other types of exceptions can also be thrown. For example, if the user does not type in any argument after the program name, then an IndexOutOfRangeException will be thrown. The code in Listing 3 below follows the good practice of trying to catch all predictable exceptions and then using Exception as the last bastion of error handling.

Listing 3: Catching all exceptions

using System;
using System.IO;

class Testing {

  public FileStream GetFileStream(String filePath) {
    try {
      FileStream fs = File.Open(filePath, FileMode.Open);
      return fs;
    }
    catch (FileNotFoundException e) {
      throw e;
    }
  }

  public static void Main(String[] args) {
    Testing t = new Testing();
    try {
      t.GetFileStream(args[0]);
      Console.WriteLine("Successful");
    }
    catch (FileNotFoundException) {
      Console.WriteLine("File Not Found");
    }
    catch (IndexOutOfRangeException) {
      Console.WriteLine("Usage: Testing filepath");
    }
    catch (Exception) {
      Console.WriteLine("Unexpected exception occurs ");
    }

  }
}

Programming C#Programming C#
By Jesse Liberty
July 2001
0-596-00117-7, Order Number: 1177
680 pages, $39.95

Now, your program is more robust. If the user forgets to type in the file path, it won't crash. It will just warn the user that they need to type a file path after the program name. Also, the last catch clause uses Exception as the argument, meaning that any unpredictable exception will also be caught.

Summary

You have seen how C# handles errors in the code using a try ... catch ... finally block. Compared to the older method of checking a function's return value and branching on error, this strategy is superior because it isolated and handled locally.

Budi Kurniawan is a senior J2EE architect and author.



Return to the .NET DevCenter.

Copyright © 2009 O'Reilly Media, Inc.