Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# 2008 Step by Step.pdf
Скачиваний:
27
Добавлен:
25.03.2016
Размер:
14 Мб
Скачать
☆

114Part I Introducing Microsoft Visual C# and Microsoft Visual Studio 2008

4.Click Quit, and return to the Visual Studio 2008 programming environment.

5.In the Code and Text Editor window displaying Window1.xaml.cs, locate the multiplyValues method. It looks like this:

private int multiplyValues(int leftHandSide, int rightHandSide)

{

expression.Text = leftHandSide.ToString() + “ * “ + rightHandSide.ToString(); return leftHandSide * rightHandSide;

}

The return statement contains the multiplication operation that is silently overflowing.

6. Edit the return statement so that the return value is checked, like this:

return checked(leftHandSide * rightHandSide);

The multiplication is now checked and will throw an OverflowException rather than silently returning the wrong answer.

7.Locate the calculateClick method.

8.Add the following catch handler immediately after the existing FormatException catch handler in the calculateClick method:

catch (OverflowException oEx)

{

result.Text = oEx.Message;

}

Tip The logic of this catch handler is the same as that for the FormatException catch

handler. However, it is still worth keeping these handlers separate rather than simply writing a generic Exception catch handler because you might decide to handle these

exceptions differently in the future.

9.On the Debug menu, click Start Without Debugging to build and run the application.

10.Type 9876543 in the left operand text box, type 9876543 in the right operand text box, select the Multiplication option, and then click Calculate.

The second catch handler successfully catches the OverflowException and displays the message “Arithmetic operation resulted in an overflow” in the Result text box.

11.Click Quit to return to the Visual Studio 2008 programming environment.

Throwing Exceptions

Suppose you are implementing a method called monthName that accepts a single int argument and returns the name of the corresponding month. For example, monthName(1) returns “January”, monthName(2) returns “February”, and so on. The question is: What should

Chapter 6 Managing Errors and Exceptions

115

the method return when the integer argument is less than 1 or greater than 12? The best answer is that the method shouldn’t return anything at all; it should throw an exception. The .NET Framework class libraries contain lots of exception classes specifically designed for situations such as this. Most of the time, you will find that one of these classes describes your exceptional condition. (If not, you can easily create your own exception class, but you

need to know a bit more about the C# language before you can do that.) In this case, the existing .NET Framework ArgumentOutOfRangeException class is just right. You can throw an

exception by using the throw statement, as shown in the following example:

public static string monthName(int month)

{

switch (month)

{

case 1 :

return “January”; case 2 :

return “February”;

...

case 12 :

return “December”; default :

throw new ArgumentOutOfRangeException(“Bad month”);

}

}

The throw statement needs an exception object to throw. This object contains the details of

the exception, including any error messages. This example uses an expression that creates a new ArgumentOutOfRangeException object. The object is initialized with a string that will populate its Message property by using a constructor. Constructors are covered in detail in

Chapter 7, “Creating and Managing Classes and Objects.”

In the following exercises, you will add to the MathsOperators project code for throwing an exception.

Throw your own exception

1.Return to Visual Studio 2008.

2.On the Debug menu, click Start Without Debugging.

3.Type 24 in the left operand text box, type 36 in the right operand text box, and then click Calculate.

The value 0 appears in the Result text box. The fact that you have not selected an

operator option is not immediately obvious. It would be useful to write a diagnostic message in the Result text box.

4.Click Quit to return to the Visual Studio 2008 programming environment.

116Part I Introducing Microsoft Visual C# and Microsoft Visual Studio 2008

5.In the Code and Text Editor window displaying Window1.xaml.cs, locate and examine the doCalculation method. It looks like this:

private int doCalculation(int leftHandSide, int rightHandSide) { int result = 0;

if (addition.IsChecked.HasValue && addition.IsChecked.Value) result = addValues(leftHandSide, rightHandSide);

else if (subtraction.IsChecked.HasValue && subtraction.IsChecked.Value) result = subtractValues(leftHandSide, rightHandSide);

else if (multiplication.IsChecked.HasValue && multiplication.IsChecked.Value) result = multiplyValues(leftHandSide, rightHandSide);

else if (division.IsChecked.HasValue && division.IsChecked.Value) result = divideValues(leftHandSide, rightHandSide);

else if (remainder.IsChecked.HasValue && remainder.IsChecked.Value) result = remainderValues(leftHandSide, rightHandSide);

return result;

}

The addition, subtraction, multiplication, division, and remainder fields are the radio buttons that appear on the form. Each radio button has a property called IsChecked that indicates whether the user has selected it. The IsChecked property is an example of a nullable value, which means it can either contain a specific value or be in an unde-

fined state. (You learn more about nullable values in Chapter 8, “Understanding Values and References.”) The IsChecked.HasValue property indicates whether the radio button is in a defined state, and if it is, the IsChecked.Value property indicates what this state is. The IsChecked.Value property is a Boolean that has the value true if the radio button

is selected or false otherwise. The cascading if statement examines each radio button in turn to find which one is selected. (The radio buttons are mutually exclusive, so the

user can select only one radio button at most.) If none of the buttons is selected, none of the if statements will be true and the result variable will remain at its initial value (0).

This variable holds the value that is returned by the method.

You could try to solve the problem by adding one more else statement to the if-else cascade to write a message to the result text box on the form. However, this solution is

not a good idea because it is not really the purpose of this method to output messages. It is better to separate the detection and signaling of an error from the catching and handling of that error.

6.Add another else statement to the list of if-else statements (immediately before the return statement), and throw an InvalidOperationException exactly as follows:

else

throw new InvalidOperationException(“no operator selected”);

7.On the Debug menu, click Start Without Debugging to build and run the application.

8.Type 24 in the left operand text box, type 36 in the right operand text box, and then click Calculate.

Chapter 6 Managing Errors and Exceptions

117

An exception dialog box appears. The application has thrown an exception, but your code does not catch it yet.

9.Click Close program.

The application terminates, and you return to Visual Studio 2008.

Now that you have written a throw statement and verified that it throws an exception, you will write a catch handler to handle this exception.

Catch your own exception

1.In the Code and Text Editor window displaying Window1.xaml.cs, locate the calculateClick method.

2.Add the following catch handler immediately below the existing two catch handlers in the calculateClick method:

catch (InvalidOperationException ioEx)

{

result.Text = ioEx.Message;

}

This code catches the InvalidOperationException that is thrown when no operator radio button is selected.

3.On the Debug menu, click Start Without Debugging.

4.Type 24 in the left operand text box, type 36 in the right operand text box, and then click Calculate.

The message “no operator selected” appears in the Result text box.

5.Click Quit.

The application is now a lot more robust than it was. However, several exceptions could still

arise that would not be caught and that might cause the application to fail. For example, if you attempt to divide by 0, an unhandled DivideByZeroException will be thrown. (Integer divi-

sion by 0 does throw an exception, unlike floating-point division by 0.) One way to solve this is to write an ever larger number of catch handlers inside the calculateClick method. However, a better solution is to add a general catch handler that catches Exception at the end of the list of catch handlers. This will trap all unhandled exceptions.

Tip The decision of whether to catch all unhandled exceptions explicitly in a method depends on the nature of the application you are building. In some cases, it makes sense to catch exceptions as close as possible to the point at which they occur. In other situations, it is more useful to let an exception propagate back to the method that invoked the routine that threw the exception.

118

Part I Introducing Microsoft Visual C# and Microsoft Visual Studio 2008

Catch unhandled exceptions

1.In the Code and Text Editor window displaying Window1.xaml.cs, locate the calculateClick method.

2.Add the following catch handler to the end of the list of existing catch handlers:

catch (Exception ex)

{

result.Text = ex.Message;

}

This catch handler will catch all hitherto unhandled exceptions, whatever their specific type.

3.On the Debug menu, click Start Without Debugging.

You will now attempt to perform some calculations known to cause exceptions and confirm that they are all handled correctly.

4.Type 24 in the left operand text box, type 36 in the right operand text box, and then click Calculate.

Confirm that the diagnostic message “no operator selected” still appears in the Result text box. This message was generated by the InvalidOperationException handler.

5.Type John in the left operand text box, and then click Calculate.

Confirm that the diagnostic message “Input string was not in a correct format” appears in the Result text box. This message was generated by the FormatException handler.

6.Type 24 in the left operand text box, type 0 in the right operand text box, select the Divide radio button, and then click Calculate.

Confirm that the diagnostic message “Attempted to divide by zero” appears in the Result text box. This message was generated by the general Exception handler.

7.Click Quit.

Using a finally Block

It is important to remember that when an exception is thrown, it changes the flow of execution through the program. This means you can’t guarantee that a statement will always

run when the previous statement finishes because the previous statement might throw an exception. Look at the following example. It’s very easy to assume that the call to reader.Close

will always occur. After all, it’s right there in the code:

TextReader reader = src.OpenText(); string line;

while ((line = reader.ReadLine()) != null)

{

Chapter 6 Managing Errors and Exceptions

119

source.Text += line + “\n”;

}

reader.Close();

Sometimes it’s not an issue if one particular statement does not run, but on many occasions it can be a big problem. If the statement releases a resource that was acquired in a previous

statement, failing to execute this statement results in the resource being retained. This example is just such a case: If the call to src.OpenText succeeds, it acquires a resource (a file handle) and you must ensure that you call reader.Close to release the resource. If you don’t, sooner or

later you’ll run out of file handles and be unable to open more files. (If you find file handles too trivial, think of database connections instead.)

The way to ensure that a statement is always run, whether or not an exception has been

thrown, is to write that statement inside a finally block. A finally block occurs immediately after a try block or immediately after the last catch handler after a try block. As long as the program enters the try block associated with a finally block, the finally block will always be

run, even if an exception occurs. If an exception is thrown and caught locally, the exception handler executes first, followed by the finally block. If the exception is not caught locally (the

runtime has to search through the list of calling methods to find a handler), the finally block runs first. In any case, the finally block always executes.

The solution to the reader.Close problem is as follows:

TextReader reader = null; try

{

reader = src.OpenText(); string line;

while ((line = reader.ReadLine()) != null)

{

source.Text += line + “\n”;

}

}

finally

{

if (reader != null)

{

reader.Close();

}

}

Even if an exception is thrown, the finally block ensures that the reader.Close statement always executes. You’ll see another way to solve this problem in Chapter 14, “Using Garbage Collection and Resource Management.”

If you want to continue to the next chapter

Keep Visual Studio 2008 running, and turn to Chapter 7.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]