Be Sharp With C# (Chapter 7, Debugging and Defensive Programming)
Be Sharp With C# (Chapter 7, Debugging and Defensive Programming)
7
Debugging and Defensive Programming
Key concepts
Syntax errors, Run-time errors
& Logic errors
Debugging
Representative test data
Exceptions and Exception
handlers
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.
Offending code
Error message
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:
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?
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)
Chapter 7 4 Debugging
Debugging
Debugging refers to the process of finding and correcting all logical errors in a program.
Something to forget
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.
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.
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:
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:
Something to do
Change the Click() event handler of the Consumption: km/l button as follows:
try
{
int iKm = int.Parse(txtDistance.Text);
double dLitre = double.Parse(txtFuel.Text);
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
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.
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.
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.
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.
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.
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.
Chapter 7 9 Debugging
Keywords
You should make sure that you know what each of these items mean or where they are used.
Key:
Concepts : Normal
Classes 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 no
circumstances 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.