Writing an Error Handler Using Try...Catch...Finally


Writing an Error Handler Using try...Catch...Finally

It's useful to have Visual C# halt execution when an exception occurs when debugging. When the code is halted while running in the IDE, you receive an error message, and you're shown the offending line of code. However, when your project is run as a compiled program, an unhandled exception causes the program to terminate (aka crash to the desktop). This is one of the most undesirable things an application can do. Fortunately, you can prevent exceptions from stopping code execution (and terminating compiled programs) by writing code specifically designed to deal with exceptions. Exception-handling code instructs Visual C# on how to deal with an exception instead of relying on Visual C#'s default behavior of aborting the application.

Visual C# supports structured exception handling (a formal way of dealing with errors) in the form of the try block. Creating structured error-handling code can be a bit confusing at first, and like most coding principles, it's best understood by doing it.

Create a new Windows Application called Structured Exception Handling and follow these steps to build the project:

1.

Right-click Form1.cs in the Solution Explorer, choose Rename, and change the name of the default form to frmExceptionHandlingExample.cs. Next, set the form's Text property to Structured Exception Handling.

2.

Add a new button to the form and set its properties as follows:

Property

Value

Name

btnCatchException

Location

104,128

Size

96,23

Text

Catch Exception


3.

Double-click the button and add the following code to its Click() event:

try {    Debug.WriteLine("Try"); } catch (Exception ex) {    Debug.WriteLine("Catch"); } finally {    Debug.WriteLine("Finally"); } Debug.WriteLine("Done Trying");


4.

The code won't work at this time because you didn't specify the full name-space reference to the Debug object. As I mentioned in an earlier chapter, you can add a using statement at the top of the class so that you don't have to provide the full qualifier each time you use the Debug object. Scroll up to the top of the class and locate the section with existing using statements, and then add the following using statement below the existing ones:

using System.Diagnostics;


As you can see, the try, catch, and finally statements use the braces ({}) to enclose statements. The TRy, catch, and finally structure is used to wrap code that may cause an exception; it provides the means of dealing with thrown exceptions. Table 15.2 explains the sections of this structure.

Table 15.2. Sections of the TRy...Catch-Finally Structure

Section

Description

try

The try section is where you place code that might cause an exception. You can place all of a procedure's code within the try section, or just a few lines.

catch

Code within the catch section executes only when an exception occurs; it's the code you write to catch the exception.

finally

Code within the finally section occurs when the code within the TRy and/or code within the catch sections completes. This section is where you place your cleanup codecode that you want always executed regardless of whether an exception occurs.


By the Way

There are three forms of try statements:

  • A TRy block followed by one or more catch blocks.

  • A try block followed by a finally block.

  • A TRy block followed by one or more catch blocks, followed by a finally block.


Press F5 to run the project and then click the button. Next, take a look at the contents of the Output window. The Output window should contain the following lines of text (among others):

Try Finally Done Trying


Here's what happened:

  1. The try block begins, and code within the try section executes.

  2. Catch sections are used to trap exceptions. Because no exception occurs, code within the catch section is ignored.

  3. When all statements within the try section finish executing, the code within the finally section executes.

  4. When all statements within the finally section finish executing, execution jumps to the statement immediately following the try, catch, and finally statements.

Stop the project now by choosing Debug, Stop Debugging from the menu.

Now that you understand the basic mechanics of the try, catch, and finally structure, you're going to add statements within the structure so that an exception occurs and gets handled.

Change the contents of the procedure to match this code:

long lngNumerator = 10; long lngDenominator = 0; long lngResult; try {     Debug.WriteLine("Try");     lngResult = lngNumerator / lngDenominator; } catch {     Debug.WriteLine("Catch"); } finally {     Debug.WriteLine("Finally"); } Debug.WriteLine("Done Trying");


Again, press F5 to run the project. Click the button and take a look at the Output window. This time, the text in the Output window should read

Try A first chance exception of type 'System.DivideByZeroException' occurred in Structured Exception Handling.exe Catch Finally Done Trying


Notice that this time the code within the catch section executes. That's because the statement that sets lngResult causes a DivideByZero exception. Had this statement not been placed within a TRy block, Visual C# would have raised the exception, and an error dialog box would've appeared. However, because the statement is placed within the TRy block, the exception is caught. Caught means that when the exception occurred, Visual C# directed execution to the catch section. (You do not have to use a catch section. If you omit a catch section, caught exceptions are simply ignored.) Notice also how the code within the finally section executes after the code within the catch section. Remember that code within the finally section always executes, regardless of whether an exception occurs.

Dealing with an Exception

Catching exceptions so that they don't crash your application is a noble thing to do, but it's only part of the error-handling process. You'll usually want to tell the user (in a friendly way) that an exception has occurred. You'll probably also want to tell the user what type of exception occurred. To do this, you must have a way of knowing what exception was thrown. This is also important if you intend to write code to deal with specific exceptions. The catch statement enables you to specify a variable to hold a reference to an Exception object. Using an Exception object, you can get information about the exception. The following is the syntax used to place the exception in an exception object:

catch (Exception variablename)


Modify your catch section to match the following:

catch (Exception objException) {     Debug.WriteLine("Catch");     MessageBox.Show("An error has occurred: " + objException.Message); }


The Message property of the Exception object contains the text that describes the specific exception that occurred. Run the project and click the button, and Visual C# displays your custom error message (see Figure 15.9).

Figure 15.9. Structured exception handling enables you to decide what to do when an exception occurs.


Handling an Anticipated Exception

At times, you'll anticipate a specific exception being thrown. For example, you might write code that attempts to open a file when the file does not exist. In such an instance, you'll probably want the program to perform certain actions when this exception is thrown. When you anticipate a specific exception, you can create a catch section designed specifically to deal with that one exception.

Recall from the previous section that you can retrieve information about the current exception using a catch statement, such as

catch (Exception objException)


By creating a generic Exception variable, this catch statement catches any and all exceptions thrown by statements within the try section. To catch a specific exception, change the data type of the exception variable to a specific exception type. Remember the code you wrote earlier that caused a format exception when an attempt was made to pass an empty string to the Convert.ToInt64() method? You could have used a try structure to deal with the exception, using code such as this:

long lngAnswer; try {     lngAnswer = 100 / long.Parse(txtInput.Text);     MessageBox.Show("100/" + txtInput.Text + " is " + lngAnswer); } catch (System.FormatException) { MessageBox.Show("You must enter a number in the text box."); } catch {      MessageBox.Show("Caught an exception that wasn't a format exception."); }


Notice that there are two catch statements in this structure. The first catch statement is designed to catch only a format exception; it won't catch exceptions of any other type. The second catch statement doesn't care what type of exception is thrown; it catches all of them. The second catch statement acts as a catch-all for any exceptions that aren't overflow exceptions because catch sections are evaluated from top to bottom, much like case statements in the switch structure. You could add more catch sections to catch other specific exceptions if the situation calls for it.

This next example, you're going to build on the Picture Viewer project last edited in Hour 11, "Using Constants, Data Types, Variables, and Arrays," so go ahead and open that project now. First, I want you to see the exception that you are going to catch. Follow these steps to cause an exception to occur:

1.

Press F5 to run the project.

2.

Click the Open Picture button on the toolbar to display the Select Picture dialog box.

3.

In the File Name: box, enter *.* and press Enter. This changes your filter so that you can now select files that aren't images. Locate a file on your hard drive that you know is not an image. Files with the extension .txt, .ini, or .pdf are perfect.

4.

After you've located a file that isn't an image file, click it to select it and then Click Open.

You have now caused an Out of Memory Exception (see Figure 15.10). This is the exception thrown by the picture box when you attempt to load a file that isn't a picture. Your first reaction might be something along the lines of "why do I have to worry about that; no one would do that." Well, welcome to programming my friend! A lot of your time will be spent writing code to protect users from themselves. It's not fair and usually not fun, but it is a reality.

Figure 15.10. You never want an unhandled exception to occurever.


Go ahead and choose Stop Debugging on the toolbar to stop the running project. Rather than take you step by step through the changes, it will be easier to just show you the code for the new OpenPicture() procedure. Change your code to the code shown here:

try {    // Show the open file dialog box.    if (ofdSelectPicture.ShowDialog() == DialogResult.OK)    {       // Load the picture into the picture box.       picShowPicture.Image = Image.FromFile(ofdSelectPicture.FileName);       // Show the name of the file in the form's caption.       this.Text = string.Concat("Picture Viewer(" +             ofdSelectPicture.FileName + ")");    } } catch (System.OutOfMemoryException) {    MessageBox.Show("The file you have chosen is not an image file.",          "Invalid File", MessageBoxButtons.OK); }


What you've just done is wrapped the procedure in an error-handler that watches for and deals with an Out Of Memory Exception. Press F5 to run the project, and follow the steps outlined earlier to load a file that isn't an image. Now, rather than receiving an exception from the IDE, your application displays a custom message box that is much more user friendly, and that won't crash the application to the desktop!

Although you have now eliminated the possibility of the user generating an Out Of Memory exception by choosing a file that isn't a valid picture, there are some caveats you should be aware of regarding the code changes you made:

  • If some other code in the procedure caused an Out Of Memory Exception, you would be misleading the user with your error message. You could address this by wrapping only the statement that loads the selected picture into the picturebox within its own try/catch structure.

  • If an exception of another type was encountered in the procedure, that error would be ignored. You can prevent this by creating a generic catch block to catch any additional exceptions.

As you can see, the mechanics of adding a TRy structure to handle exceptions is relatively easy, whereas knowing what specifically to catch and how to handle the situation when an exception is caught can prove to be challenging.




Sams Teach Yourself Microsoft Visual C# 2005 in 24 Hours, Complete Starter Kit
Sams Teach Yourself Visual C# 2005 in 24 Hours, Complete Starter Kit
ISBN: 0672327406
EAN: 2147483647
Year: N/A
Pages: 248
Authors: James Foxall

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net