Handling Errors
The best way to handle errors is to not give the user the ability to make them in the first place. For
example, suppose a program can take purchase orders for between 1 and 100 reams of paper. If
the program lets you specify the quantity by using a
NumericUpDown control with Minimum = 1
and
Maximum = 100, you cannot accidentally enter invalid values like –5 or 10,000.
Sometimes, however, it’s hard to build an interface that protects against all possible errors. For
example, if the user needs to type in a numeric value, you need to worry about invalid inputs
such as 1.2.3 and ten. If you write a program that works with files, you can’t always be sure the
le will be available when you need it. For example, it might be on a CD or floppy disk that has
been removed, or it might be locked by another program.
In this lesson, you learn how to deal with these kinds of unexpected errors. You learn how to
protect against invalid values, unavailable files, and other problems that are difficult or impos-
sible to predict in advance.
ERRORS AND EXCEPTIONS
An error is a mistake. It occurs when the program does something incorrect. Sometimes an
error is a bug, for example, if the code just doesn’t do the right thing.
Sometimes an error is caused by circumstances outside of the program’s control. If the program
expects the user to enter a numeric value in a textbox but the user types 1.2.3, the program wont
be able to continue its work until the user fixes the problem.
Sometimes you can predict when an error may occur. For example, if a program needs to open
a file, there’s a chance that the file wont exist. In predictable cases such as this one, the program
should try to anticipate the error and protect itself. In this case, it should check to see if the file
exists before it tries to open it. It can then display a message to the user and ask for help.
Other errors are hard or impossible to predict. Even if thele exists, it may be locked by
another program. The user entering invalid data is another example. In those cases, the
program may need to just try to do its job. If the program tries to do something seriously
invalid, it will receive an exception.
21
596906book.indd 251 4/8/10 7:40:26 AM
252
LESSON 21 Handling Errors
An exception tells the program that something generally very bad occurred such as trying to divide by
zero, trying to access an entry in an array that doesn’t exist (for example, setting
values[100] = 100
when
values only holds 10 items), or trying to convert “ten” into an integer.
In cases like these, the program must catch the exception and deal with it. Sometimes it can figure
out what went wrong and fix the problem. Other times it might only be able to tell the user about
the problem and hope the user can fix it.
In C# terms, the code that has the problem throws the exception. Code higher
up in the chain can catch the exception and try to handle it.
To catch an exception, a program uses a try-catch block.
TRYCATCH BLOCKS
In C#, you can use a try-catch block to catch exceptions. One common form of this statement has
the following syntax:
try
{
...codeToProtect...
}
catch (ExceptionType1 ex)
{
...exceptionCode1...
}
catch (ExceptionType2 ex)
{
...exceptionCode2...
}
finally
{
...finallyCode...
}
Where:
codeToProtect
The code that might throw the exception.
ExceptionType1, ExceptionType2
These are exception types such as FormatException
or
DivideByZeroException. If this particular exception type occurs in the codeToProtect,
the corresponding
catch block executes.
ex
A variable that has the type ExceptionType. You pick the name for this variable. If an
error occurs, you can use this variable to learn more about what happened.
exceptionCode
The code that the program should execute if the corresponding
exception occurs.
finallyCode
This code always executes whether or not an error occurs.
596906book.indd 252 4/8/10 7:40:26 AM
Try-Catch Blocks
253
A try-catch-finally block can include any number of catch blocks with different exception types.
If an error occurs, the program looks through the
catch blocks until it finds one that matches the
error. It then executes that block’s code and jumps to the
finally statement if there is one.
If you use a
catch statement without an exception type and variable, that block catches all
exceptions.
If you omit the catch statements exception type and variable, the code
cannot learn anything about the exception that occurred. Sometimes thats
okay if you don’t really care what went wrong as long as you know that
something went wrong. An alternative strategy is to catch a generic
Exception
object, which matches any kind of exception and provides more information.
Then you can at least display an error message as shown in the following code,
which tries to calculate a students test score average assuming the variables
totalScore and numTests are already initialized. If the code throws an excep-
tion, the
catch block displays the exception’s default description.
try
{
// Try to divide by zero.
int averageScore = totalScore / numTests;
// Display the student’s average score.
MessageBox.Show(“Average Score: “ + averageScore.ToString
(“0.00”));
}
catch (Exception ex)
{
// Display a message describing the exception.
MessageBox.Show(“Error calculating average. ” + ex.Message);
}
In this example the error that this code is most likely to encounter is a
DivideByZeroException thrown if numTests is 0. Because that kind of error
is predictable, the code should probably specifically look for it. Better still, it
should check
numTests and not perform the calculation if numTests is 0. Then
it can avoid the exception completely. The best strategy is to catch the most
specific type of exception possible to get the most information. Then catch
more generic exceptions just in case.
A try-catch-finally block must include at least one catch block or the finally block, although
none of them needs to contain any code. For example, the following code catches and ignores all
exceptions:
try
{
...codeToProtect...
}
596906book.indd 253 4/8/10 7:40:26 AM
254
LESSON 21 Handling Errors
catch
{
}
The code in the finally block executes whether or not an exception occurs. If an error
occurs, the program executes a
catch block (if one matches the exception) and then executes the
finally block. If no error occurs, the program executes the finally block after it finishes
the
codeToProtect code.
In fact, if the code inside the
try or catch section executes a return statement, the finally block
still executes before the program actually leaves the method!
THROWING ERRORS
Occasionally it’s useful to be able to throw your own errors. For example, consider the factorial
function you wrote in Lesson 20 and suppose the program invokes the function passing it the value
–10 for its parameter. The value –10! is not defined, so what should the function do? It could just
declare that –10! is 1 and return that, but that approach could hide a potential error in the rest of
the program.
A better solution is to throw an exception telling the program what’s wrong. The calling code can
then use a
try-catch-finally block to catch the error and tell the user whats wrong.
The following code shows an improved version of the factorial function described in Lesson 20.
Before calculating the factorial, the code checks its parameter and, if the parameter is less than zero,
it throws a new
ArgumentOutOfRangeException. The exception’s constructor has several overloaded
versions. The one used here takes as parameters the name of the parameter that caused the problem
and a description of the error.
// Return value!
private long Factorial(long value)
{
// Check the parameter.
if (value < 0)
{
// This is invalid. Throw an exception.
throw new ArgumentOutOfRangeException(
“value”,
“The Factorial parameter must be at least 0.”);
}
// Calculate the factorial.
long result = 1;
for (long i = 2; i <= value; i++)
{
result *= i;
}
return result;
}
596906book.indd 254 4/8/10 7:40:26 AM
Try It
255
The following code shows how the program might invoke the new version of the Factorial function.
It uses a
try-catch block to protect itself in case the Factorial function throws an error. The block
also protects against other errors such as the user entering garbage in the textbox.
// Calculate the factorial.
private void calculateButton_Click(object sender, EventArgs e)
{
try
{
// Get the input value.
long number = long.Parse(numberTextBox.Text);
// Calculate the factorial.
long answer = Factorial(number);
// Display the factorial.
resultTextBox.Text = answer.ToString();
}
catch (Exception ex)
{
// Display an error message.
MessageBox.Show(ex.Message);
resultTextBox.Clear();
}
}
Exceptions take additional overhead and disrupt the natural flow of code mak-
ing it harder to read, so only throw exceptions to signal exceptional conditions.
If a method needs to tell the calling code whether it succeeded or failed, that
isn’t an exceptional condition so use a return value. If a method has an invalid
input parameter (such as a 0 in a parameter that cannot be 0), that’s an error, so
throw an exception.
TRY IT
In this Try It, you add validation and error handling code to the program you built for Lesson 19s
Exercise 4. When the user clicks the NewItemForm’s Calculate and OK buttons, the program
should verify that the values make sense and protect itself against garbage such as the user entering
the quantity “one,” as shown in Figure 21-1.
You can download the code and resources for this Try It from the book’s web
page at
www.wrox.com or www.CSharpHelper.com/24hour.html. You can find
the code in the Lesson21 folder.
596906book.indd 255 4/8/10 7:40:27 AM
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.139.172