C# Exception Programming

In document C# Network Programming (Page 48-51)

One of the biggest problems for programmers is dealing with abnormal conditions in a program. Inexperienced programmers often forget to compensate for error conditions such as dividing by zero. This results in ugly and annoying error messages and programs blowing up in customers faces. To ensure that your code is user-friendly, try to compensate for most types of error conditions. Such error conditions, or other unexpected behavior occurring when a program executes, are called exceptions. Listing 1.7 shows an example.

Listing 1.7: The BadError.cs program

using System;

class BadError {

public static void Main () {

int var1 = 1000, var2 = 0, var3;

var3 = var1 / var2;

Console.WriteLine("The result is: {0}", var3);

} }

As you can see, this program is doomed from the start. The arithmetic function in line 9 is destined for disaster because of a divide-by-zero error. Compile and run this example and watch what happens:

C:\>csc BadError.cs

Microsoft (R) Visual C# .NET Compiler version 7.00.9466 for Microsoft (R) .NET Framework version 1.0.3705

Copyright (C) Microsoft Corporation 2001. All rights reserved.

C:\>BadError

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.

at BadError.Main() C:\>

The csc compiler had no problem compiling this code. It was oblivious to the impending error. When the program runs, a pop-up window indicates that an error occurred and asks you if you want to debug the application. This is exactly the kind of thing you do not want your customers to see. After clicking the OK button, the text error message is produced on the console, indicating the error that was encountered. The program halts at the line of code that produced the error, and no other lines are executed.

C# helps programmers code for exceptions by providing a way to watch and capture exceptions as they occur. By catching exceptions, programmers can efficiently provide for readable error messages and the continuation of the program, or they can stop the program gracefully if necessary. In C#, the try-catch block accomplishes this.

The try-catch block tries to execute one or more statements. If any of the statements generates an exception, the catch block of code is executed instead of the program stopping. Depending on what you include in the catch block, the program can either be terminated gracefully, or allowed to continue as if nothing were wrong. Here is the format of a try-catch block:

try {

// one or more lines of code }

catch () {

// one or more lines of code to execute if an error }

finally {

// one or more lines of code to execute at all times }

The statements in the try block are executed as normal within the course of the program. If an error condition occurs within the try block, program execution moves to the catch block. After the code in the catch block is executed, control passes back to the main program statements that follow the try-catch block, as if no error had occurred (unless of course the code in the catch block stops or redirects the program execution).

Optionally, you can add a finally block, which will be executed after the try or the catch blocks are finished.

Sometimes the finally block is used for clean-up functions that must run whether the functions succeed or fail; most often, however, finally is not used.

Note

Notice the parentheses in the catch statement. This is a filter, allowing you to define what types of exceptions you want to attempt to catch. You can define a specific exception to watch for, depending on the type of actions being done in the try block; or you can define the generic Exception class, which will catch any exception that occurs. You can even define more than one catch block. Catch blocks are evaluated in order, so specific exceptions must be listed before general ones.

Listing 1.8 shows an example of a simple try-catch block.

Listing 1.8: The CatchError.cs program

using System;

class CatchError {

public static void Main () {

int var1 = 1000, var2 = 0, var3;

try {

var3 = var1 / var2;

}

catch (ArithmeticException e) {

Console.WriteLine("Exception: {0}", e.ToString());

var3 = -1;

}

catch (Exception e) {

Console.WriteLine("Exception: {0}", e.ToString());

var3 = -2;

}

Console.WriteLine("The result is: {0}", var3);

} }

In CatchError, the original program is modified by adding a try-catch block. There are two catch statements: one to watch specifically for ArithmeticExceptions, and one to watch for any general Exception. Notice that the specific ArithmeticException was listed first, otherwise the general Exception block would handle all of the exceptions before the more detailed exception appeared. Also note that the catch blocks set a value for the result variable that can then be checked later on in the program. The result of this program is as follows:

C:\>csc CatchError.cs

Microsoft (R) Visual C# .NET Compiler version 7.00.9466 for Microsoft (R) .NET Framework version 1.0.3705

Copyright (C) Microsoft Corporation 2001. All rights reserved.

C:\>CatchError

Exception: System.DivideByZeroException: Attempted to divide by zero.

at CatchError.Main() The result is: -1 C:\>

The try-catch block gracefully catches the arithmetic exception, displays the error as instructed in the catch block, and sets the variable to a special value that can later be checked in the program logic.

Note

Network functions are frequently used within try-catch blocks. In network programming, it is often impossible to determine whether an action will

succeed. For example, packets sent out on the network may not get to their intended destination because of a down router or destination host. Instead of the program blowing up because of an unexpected network issue, the problem can be reported to the user.

In document C# Network Programming (Page 48-51)