Search & Destroy 101

Debugging Windows Forms Run-time Errors

asp:Feature

LANGUAGES: C#

ASP.NET VERSIONS: 2.0

 

Search & Destroy 101

Debugging Windows Forms Run-time Errors

 

By Asif Sayed

 

How often do you hear from one of your peers, I m busy debugging my code ? As I see it, debugging and code development go hand-in-hand for every developer. Although debugging is becoming easier and more innovative with every release of Visual Studio, beginning developers can find it very challenging. In this article, I ll show you a simple step-by-step tutorial for finding bugs that will help you in becoming a code warrior (see Figure 1). I assume the reader has a basic understanding of the Visual Studio 2005 IDE. You should also be comfortable writing code with C#.

 


Figure 1: Example in run-time mode.

 

What Is Debugging?

To understand what debugging is, you must know what a bug is! Put simply, a bug is any unwanted result of code. So, what does a bug do? Simple; it produces an error and you know what happens when an error is produced. Debugging is the process by which you remove such bugs and prevent errors.

 

The quality of an application is partly determined by the amount of debugging effort spent on it. No wonder we usually build a project in debug mode. However, no matter how much care is taken, it s nearly impossible to make truly bug-free code. Even the most experienced developer can introduce a bug by making a silly mistake. However, with the strong debugging support built in to Visual Studio, we can easily tackle even the most notorious bug.

 

Different Types of Errors

What are the different types of errors that bugs can produce? Let s divide them into the following three categories:

  • Design-/compile-time error (mostly syntax errors)
  • Run-time error
  • Logical error

 

Design-time errors are the most friendly of errors, because most of them can be identified during compilation and fixed without much hassle. The Visual Studio IDE features IntelliSense, which helps highlight potential errors before you even compile. Run-time errors which often cause a panic are bad, especially if they crash your application during a demo session. Last on the list is the logical error. Here you graduate from panicking to hair pulling.

 

Bugs that produce logical errors are nasty because the compiler doesn t complain about them, so you won t get a run-time error. However, you also won t get the result you expect. In such scenarios, the debugger is most handy. Imagine you are calculating average sales for each month. The formula is simple, average sales per month = total sales / 12 . But maybe at some point in your code you are dividing by 13 instead of 12. The result won t be correct. Debugging will help find and replace the error.

 

To demonstrate the technique of debugging, we must create a bug (a rare case where you are deliberately trying to create a bug). Creating a run-time bug is not very difficult, and you can probably see many situations in the preceding average sales example that will result in a run-time error. For example, how about Divided by Zero ? Or Array index out of the range error?

 

Let s go ahead and create a simple application that will produce a table of two and store the result in an array of 10 subscripts. We ll introduce the error in a loop, in which we read from the array and display the table using a multiline TextBox control (see Figure 2); one button will produce the table and another one will result in a run-time error.

 

Let s create a Windows Application project following these steps:

  • Click on menu File | New | Project, or you can press the hot key, Ctrl + Shift + N (again, see Figure 2).
  • From the New Project dialog box select Visual C# | Windows.
  • From Templates select Windows Application.
  • Name the application; I ve called the project WinDebug101 . You may choose a different location for storing the application files according to your preference.
  • Click the OK button to finish the process. VS 2005 will create a new project; your project should resemble Figure 3.

 


Figure 2: Create a new Windows Application project.

 


Figure 3: The newly created project.

 

Most of you will see something similar to the project shown in Figure 3. You should see a blank Form1 created for you because of a new project. First, let s set a couple of properties of Form1 according to the properties listed in Figure 4. If the property toolbox is not visible in the IDE, hit the F4 key to make it visible. Pease make sure to select Form1 before applying changes to properties using the property toolbox.

 

Property

Value

Text

Windows Forms debugging 101

Size

300, 300

Figure 4: The properties of Form1.

 

Now let s add controls to the newly created Form1. As you can see in Figure 1, this example is a simple test harness for demonstrating the creation of a bug. We ll have one TextBox control to enter and format text, and two Button controls to interact with the database. Let s start by adding these controls on Form1. Make sure your Form1 looks similar to that shown in Figure 5.

 


Figure 5: Form1 designer surface after adding controls.

 

Please change the properties of the controls on the form according to Figure 6. Properties can be changed by selecting the control and using the properties toolbox. Figure 7 illustrates a graphical illustration of the process.

 

Control

Property

Value

textBox1

Multiline

True

Button1

Text

Table with no Bug

Button2

Text

Table with Bug

Figure 6: Properties of the controls on Form1.

 


Figure 7: Changing the properties of controls on Form1.

 

Now let s write some C# code to bring life to Form1. Make sure the code-behind of Form1 looks like that shown in Figure 8.

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace WinDebug101

{

 public partial class Form1 : Form

 {

   public Form1()

   {

     InitializeComponent();

   }

   private void button1_Click(object sender, EventArgs e)

   {

     string[] TableOfTwo = new string[10];

     int i;

    

     // loop to calculate the table

     for (i = 0; i < 10; i++)

     {

       // 2 x 1 = 2...

       TableOfTwo[i] = "2 x " + Convert.ToString(i+1) +

           " = " + Convert.ToString(2 * (i + 1));

     }

     // loop to display the table

     for (i = 0; i < 10; i++)

     {

       // 2 x 1 = 2...

       textBox1.Text = @textBox1.Text +

           TableOfTwo[i] + "\r\n";

     }

   }

   private void button2_Click(object sender, EventArgs e)

   {

     string[] TableOfTwo = new string[10];

     int i;

     // loop to calculate the table

     for (i = 0; i < 10; i++)

     {

       // 2 x 1 = 2...

       TableOfTwo[i] = "2 x " + Convert.ToString(i + 1) +

           " = " + Convert.ToString(2 * (i + 1));

     }

     // loop to display the table

     for (i = 0; i < 11; i++)

     {

       // 2 x 1 = 2...

       textBox1.Text = @textBox1.Text +

           TableOfTwo[i] + "\r\n";

     }

   }

 }

}

Figure 8: Bring life to Form1.

 

Code Analysis

As you can see, the code is a simple loop to produce an array containing two items. The first loop does the calculation and stores the result in an array. The second loop reads through the array and displays the result in a multi-line textbox. The code inside the button1_click event is the good code that will calculate and display the table output without error.

 

The code inside the button2_click event is the bad code, which will produce a run-time error because of the bug we introduced. Can you spot the bug? If you see the type of error, it s easy to figure out where the bug is. If you look back at Figure 1, it says Index was outside the bounds of the array. This means the loop that displays the result is trying to access an array item that is outside its limits. So, the only difference between the code in both button event handlers is:

 

// loop to display the table

for (i = 0; i < 11; i++)

{

   // 2 x 1 = 2...

  textBox1.Text = @textBox1.Text + TableOfTwo[i] + "\r\n";

}

 

As soon we try to access the eleventh physical array element, this bug causes the program to come to an immediate halt, resulting in the run-time error. You may also notice I m purposely not using try...catch here so that I can display the error within the IDE.

 

Now let s build and run the example. We can build the project several ways. If you have one project in the solution, then building the solution and the project are essentially the same. You can click the small green Play button on the main toolbar, or hit F5 on the keyboard to start the application. Also, make sure to build using debug mode (see Figure 9).

 


Figure 9: Project build.

 

If all goes well and the program compiles, you should be able to run the application. Click the Table with no Bug button; this will cause the textbox to be populated with 10 values. If you click the Table with Bug button instead, the IDE will complain about the run-time error (which should look similar to what is shown in Figure 1).

 

Now let s debug our run-time error. As you can see in Figure 1, when a run-time error occurs, the execution of the program halts where it encounters the error. In our example, the execution stops while running the loop, which displays the table. Here s the code snippet:

 

// loop to display the table

  for (i = 0; i < 11; i++)

  {

    // 2 x 1 = 2...

    textBox1.Text = @textBox1.Text + TableOfTwo[i] + \r\n ;

 }

 

When the program stops at the line inside the loop, what does it mean to you as a developer? Obviously this line has some functionality that is violating something! What other information is given to you by the IDE to help you get rid of this bug?

 

When an error happens, the code throws an exception. This is your primary channel of information as to what has happened and why. In our example, the type of the exception is IndexOutOfRangeException. What does it mean? As you can see, we re using an array, and the type of exception is telling you something is wrong with the index range. The more bugs like this you encounter, the better your debugging skills will get and the faster you will be able to detect and correct these types of errors.

 

In addition to the exception details, Visual Studio also provides some different feedback windows that can help you quickly diagnose and resolve the error. One such feedback window is the Locals window, which displays all the locally scoped variables and their values. As you can see in Figure 10, we can see the current contents of the TableOfTwo[]array here. Usually by analyzing the value of a variable, you can easily spot the bug.

 


Figure 10: Feedback windows in debug mode.

 

The Watch window is another helpful debugging feature you can use to monitor the value of any given object. Let s say you d like to track the value of the fourth physical element of the array. You can do so by switching to the Watch window (in this case Watch1) and type TableOfTwo[3] , then press Enter to see that the value column will display 2 x 4 = 8 (see Figure 11 for a graphical illustration).

 


Figure 11: The Watch window in action.

 

In many cases, you ll need to step through the code line by line until you encounter the error. This debugging method will usually give you a better idea of what happened to cause the error. This process can be done easily while in debug mode. The first step is to decide which line of code on which to pause the execution of the running application. This is commonly referred to as setting a break point, and can be accomplished by either clicking in the gray area just to the left of the line of code or by pressing F9. A red bullet mark will appear in the gray area if the break point was successfully set.

 

Once the application is paused, you can take control of the code execution and move step-by-step until you hit the error. In this case, it makes sense to set the break point inside the loop on the for statement so you can query the values of the current array item for each execution of the loop (see Figure 12 for the breakpoint setup).

 


Figure 12: Setting a break point.

 

As you can see in Figure 13, once the breakpoint is set up properly, you can step through the code in the following ways:

  • Step Into Debug | Step Into (F11 key)
  • Step Over Debug | Step Over (F10 key)
  • Step Out Debug | Step Out (Shift + F11 key)

 


Figure 13: Stepping through in debug mode.

 

Step Into means execute the current line of code and if the next line is a call to another method, the yellow code pointer will move to that code segment. Step Over means the yellow pointer will move to the next line in the current code segment without following in to any local methods that might be called by the current line. Step Out means completely execute the code in the current method and move the yellow pointer to the next line in the calling method.

 

If you d like the program execution to continue as normal, select Debug | Step Over or hit F5. You also can start and stop debug by selecting the appropriate command from the Debug menu. You also can access all these features with the help of the Debug toolbar (see Figure 14).

 


Figure 14: The Debug toolbar.

 

Conclusion

As you can see, it is easy to use the powerful debugging features of the Visual Studio IDE. With this article I introduced the debugging process, which I hope the beginner-level audience will find especially useful in finding and fixing errors in their code. Thank you for reading; as always, I look forward to your comments and suggestions feel free to drop me a line at mailto:[email protected].

 

Files accompanying this article are available for download.

 

Asif Sayed has more than 15 years of experience in software development and business process architecture. A senior systems analyst with Direct Energy in Toronto, Canada, he also teaches .NET technologies at Centennial College in Scarborough, Ontario. He is the author of Client-Side Reporting with Visual Studio in C# (Apress, 2007). Contact him at mailto:[email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish