be sharp with c# (chapter 7, debugging and defensive programming)

9
Chapter Seven 7 Debugging and Defensive Programming After this chapter you should be able to distinguish between the different types of errors and how to deal with them understand what is meant with the term debugging and how to apply it in Vi sual Studio understand what is meant with defensive programming and how to make provision for user errors Key concepts Syntax errors, Run-time errors & Logic errors Debugging Representative test data Exceptions and Exception handlers

Upload: pieter-blignaut

Post on 18-Nov-2014

504 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter Seven

7Debugging and Defensive Programming

After this chapter you should

be able to distinguish between the differenttypes of errors and how to deal with them

understand what is meant with the termdebugging and how to apply it in Visual Studio

understand what is meant with defensiveprogramming and how to make provision foruser errors

Key concepts

Syntax errors, Run-time errors& Logic errors

Debugging

Representative test data

Exceptions and Exceptionhandlers

Page 2: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 2 Debugging

Errors

Programmers are human and may make mistakes. We will discuss the categories of errors at

the hand of the example of Chapter 3, AverageAge:

Syntax errors occur when the programmer do not obey the rules of the language. For

example, he can omit a semicolon, add variables of different types, forget to enter the

appropriate parameters in a method, have mismatched curly braces or brackets, make a

spelling mistake with a variable name, object, class or method, etc.

This type of error is the easiest to detect since the compiler picks it up and presents an

error message. Change the Click() event handler of the Calculate average button as in

the screen print below. Run the program and look what happens.

The offending code is underlined with a blue wavy line. You can also view the error

message by pausing the mouse over the wavy underline. Read the message carefully – it

speaks for itself: The Text property of a text box contains data of type string. You cannot

assign string data to a variable that has been declared as int.

Run-time errors are not picked up in design mode and the program compiles perfectly.

During run-time, however, the program might crash. If, for example, the user types an

invalid number in the txtAge1 text box of the example above (after you corrected the

syntax error), he will get a run-time error with a message as in the example below:

Error message

Offending code

Page 3: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 3 Debugging

Of course, a good programmer should make provision for this kind of error as users are

also human and would be very annoyed if a program does not inform them of the error

politely and allow them to correct it. We will return to this later. For now, just press Shift-

F5 to exit the program and run it again.

Logic errors are the most difficult to pick up. The program compiles, it does not give any

run-time errors but the output is wrong. Sometimes you will realise it, but it may also

happen that you do not pick it up since the computations are too complex to check

manually. See if you can pick up the error in the following code. What is the easiest way

to correct it?

int iAge1 = int.Parse(txtAge1.Text);int iAge2 = int.Parse(txtAge2.Text);double dAverageAge = iAge1 + iAge2 / 2.0;MessageBox.Show("The average age is " + dAverageAge.ToString());

It is extremely important to test a program with representative test data that is simple

enough to check. If your program gives the correct output for a variety of input data,

chances are good that it will also provide the correct output for complex data.

"In our profession, precision and perfection are not a dispensable luxury,but a simple necessity." (Niklaus Wirth)

Page 4: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 4 Debugging

Debugging

Debugging refers to the process of finding and correcting all logical errors in a program.

Something to forget

Rear Admiral Grace Murray Hopper (1906 – 1992) was an

American computer scientist and United States Naval officer. A

pioneer in the field, she was one of the first programmers of the

Harvard Mark I computer, and she developed the first compiler for a

computer programming language (COBOL).

While she was working on a Mark II Computer at Harvard University

(somewhere in the 1940's), her associates discovered a moth stuck

in a relay and thereby impeding operation, whereupon she

remarked that they were "debugging" the system. However, the

term "bug" in the meaning of technical error dates back at least to

1878 and Thomas Edison. Debugging seems to have been used as

a term in aeronautics before entering the world of computers. Indeed, Grace Hopper

acknowledged herself that she was not coining the term. The moth fit the already existing

terminology, so she saved it.

(Source: Wikipedia)

Something to do

Click on Debug / Windows/ Locals to display the Locals window at the bottom of the screen.Note that this window is only available while the program is running.

Click in the margin next to the line of code to create a breakpoint. You can also press F9

for the same effect.

Run the program normally. Program execution will stop at the breakpoint.

Hover the mouse over a variable name. A pop-up message will appear that will indicate

the value of the parameter at the moment.

Press F10 repeatedly to step through the program line by line. You can at any time press

F5 again to stop debugging and continue with program execution normally.

Inspect the changes in the values of the variables as you progress through the program.

Page 5: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 5 Debugging

Something to understand

Debugging allows you to follow the logic of a program step-by-step so that you can identify

the place where a program goes off the track.

Use representative test data that is simple enough that you will be able to identify errors in

the values when they occur.

The Locals window shows all variables in the current scope with their values.

You can also add one or more variables to one of four Watch windows. While the Locals

window shows all variables in the current scope, you can selectively inspect the values of

variables or expressions in the Watch windows.

Defensive programming

As mentioned above, a good programmer should make provision for invalid input by users.

Users should be informed politely about their mistakes and allowed the opportunity to correct

them. Run-time errors are unforgiveable. If they occur, users cannot blame the computer and

programmers cannot blame users for being "stupid". Programmers should anticipate any kind

of error and make provision for it.

Something to do

Consider the following scenario: You want to calculate the fuel consumption of your car in

kilometre per litre as well as litre per 100 km. The distance travelled and the amount of

fuel will be available as inputs to the program.

Start with a new project, Fuel Consumption.

Design a form as in the example below.

Write the code for the Close button.

Enter the following code for the Consumption: km/l button:

private void btnKmPerLitre_Click(object sender, EventArgs e)

{

int iKm = int.Parse(txtDistance.Text);

double dLitre = double.Parse(txtFuel.Text);

double dConsumption = iKm / dLitre;

MessageBox.Show(dConsumption.ToString("0.0") + " km/l", "Fuel consumption");

}

Page 6: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 6 Debugging

Run the program with the following sets of test data:

Distance(km)

Fuel

(l)Expected output

(km/l)Actual output

(km/l)

600 50 12 12.0600 0 Message: Invalid input Run-time error600 -50 Message: Invalid input -12.050 600 Message: Unrealistic input 0.16oo 50 Message: Invalid input Run-time error

595.8 50 11.9 Run-time error600 50.6 11.9 11.9

Things to understand

Five of the seven combinations provide output that is different from what is expected. It is

very important that a programmer tests a program with test data that is representative of

all possible scenarios, even if they seem to be highly unlikely.

Changing the code to the following would solve the first two of the five problems:

int iKm = int.Parse(txtDistance.Text);

double dLitre = double.Parse(txtFuel.Text);

if (dLitre > 0)

{

double dConsumption = iKm / dLitre;

MessageBox.Show(dConsumption.ToString("0.0") + " km/l",

"Fuel consumption");

}

else

MessageBox.Show("Invalid input.", "Fuel consumption",

MessageBoxButtons.OK, MessageBoxIcon.Error);

Changing the if statement to the following would cater for the third problem:

if ((dLitre > 0) && (iKm > dLitre))

This leaves us with the problem of invalid numeric input.

Something to do

Change the Click() event handler of the Consumption: km/l button as follows:

“For a long time it puzzled me how something so expensive, so leadingedge, could be so useless. And then it occurred to me that a computeris a stupid machine with the ability to do incredibly smart things, whilecomputer programmers are smart people with the ability to doincredibly stupid things. They are, in short, a perfect match.”(Bill Bryson)

Note thedifferencebetween 600and 6oo

Page 7: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 7 Debugging

try{

int iKm = int.Parse(txtDistance.Text);double dLitre = double.Parse(txtFuel.Text);

if ((dLitre > 0) && (iKm > dLitre)){

double dConsumption = iKm / dLitre;MessageBox.Show(dConsumption.ToString("0.0") + " km/l",

"Fuel consumption",MessageBoxButtons.OK, MessageBoxIcon.Information);

}else

MessageBox.Show("Invalid input.", "Fuel consumption",MessageBoxButtons.OK, MessageBoxIcon.Error);

}catch{

MessageBox.Show("Invalid input.", "Fuel consumption",MessageBoxButtons.OK, MessageBoxIcon.Error);

}

Run the program with the same sets of test data as above. Make sure that you get the

expected output for all combinations.

Things to understand

An exception occurs because of invalid user actions or circumstances during run-time. An

exception handler is a block of code that is executed when an exception occurs.

Some exceptions can be handled by a normal if statement.

The try … catch structure will catch occurrences where input values cannot be parsed into

the expected numeric data type.

- The program attempts to execute the code in the try block. If it succeeds, the code in

the catch block is skipped. If it encounters a problem, execution is immediately

transferred to the catch block.

- Put a breakpoint on the first line inside the try block. Then run the program and enter

invalid data for the distance that was travelled. Watch how all subsequent code in the

try block is skipped.

- Make sure that you don't have any code in the catch block that could cause an error.

- The braces are not optional if there is only one statement as was the case for if or

else.

Understand the MessageBox.Show() method

The MessageBox.Show() method has 21 overloaded versions. The version that we used

here takes four parameters. The first two parameters are the standard ones for the

prompt and caption.

Page 8: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 8 Debugging

The third parameter allows the programmer to decide which buttons must be displayed. If

it is omitted, only the OK button is displayed by default. Thanks to IntelliSense, we don't

have to remember the exact naming of the class or the buttons.

- Type 'M' and select MessageBoxButtons from the dropdown list.

- Type period ('.') and select OK from the dropdown list.

The fourth parameter allows the programmer to select an icon to be displayed in the

message box. If it is omitted, no icon is displayed.

- Type 'M' again and select MessageBoxIcon from the dropdown list.

- Type period ('.') and select Information from the dropdown list.

Something to do

Change the catch block as follows and run the program with invalid data.

catch (Exception exception){

MessageBox.Show(exception.Message, "Fuel consumption",MessageBoxButtons.OK, MessageBoxIcon.Error);

}

Things to understand

The catch statement can take an optional parameter that should be an object of an

exception class. There are several exception classes available, e.g. Exception,

FormatException, DivideByZeroException, ArithmeticException.

- The generic exception class is Exception which does not always provide specific

information about the exception that occurred.

- See also http://msdn.microsoft.com/en-us/library/aa664610(VS.71).aspx

The exception object has a property Message, that contains a system generated message

about the error that occurred. You can decide to display this message with or instead of

your own.

The try … catch structure has another block, finally, which is optional and will become

of value when we start to work with files.

Page 9: Be sharp with C# (Chapter 7, Debugging and Defensive Programming)

Chapter 7 9 Debugging

Keywords

You should make sure that you know what each of these items mean or where they are used.

ArithmeticException

Breakpointscatch

DebuggingDefensive programmingDivideByZeroException

ErrorError message

ExceptionException

Exception handlerfinallyFormatException

Locals windowLogic errorMessage

Run-time errorSyntax errorTestTest datatry

Watch windows

Key:

Concepts : NormalClasses and Controls : Green, e.g. Color

Properties : Bold, e.g. Message

Reserved words : Blue, e.g. new

Exercises

Do the following exercises again while making provision for all types of errors. Under nocircumstances should a user be able to break your program.

You can in many cases replace text boxes with NumericUpDown controls. This will force the

user to enter numeric values in a specified range. It has a Value property that returns a

decimal value that can be cast to double or int or whatever is applicable for the application.

Chapter 3, Number 1 (Use NumericUpDown)

Chapter 3, Number 2Chapter 3, Number 3Chapter 3, Number 4 (Make also sure that the user cannot enter a negative exchange rate or dollar

value)Chapter 3, Number 6 (Use NumericUpDown. Make provision for any realistic Fahrenheit temperature.

Allow one decimal digit.)Chapter 3, Number 7 (Make sure that the amount and periods are larger than 0. The rate must be

between 0 and 100 inclusive)Chapter 3, Number 8 (The radius may not be less than 0)Chapter 3, Number 9

Chapter 4, Number 3Chapter 4, Number 4 (Radius and length must be larger than 0)Chapter 4, Number 5 (Prices must be larger than 0. Amount offered must be larger or equal than

total owed.)Chapter 4, Number 6 (Sales must not be less than 0.)Chapter 4, Number 7 (It is not possible to obtain the square root of a negative number.)Chapter 4, Number 8

Chapter 5, Number 1 (All marks must be larger or equal than 0 and less or equal than 100.)

Chapter 6, Number 2 (Use NumericUpDown)

Chapter 6, Number 7Chapter 6, Number 8 (Sides must be larger than 0)Chapter 6, Number 9Chapter 6, Number 11Chapter 6, Number 12Chapter 6, Number 13 (Salry must be larger than 0)