Debugging
AAHC

Click on A to make all fonts on the page smaller.

Click on A to make all fonts on the page larger.

Click on HC to toggle high contrast mode. When you move your mouse over some bold words in high contrast mode, related words are automatically highlighted. Text is shown in black and white.


In this lesson, we'll dig deeper into how to debug our programs, and discuss the difference between compile-time and runtime errors. We'll also cover how to output debug statements, use debug breakpoints, evaluate variables at runtime, trace our code using the call stack, and so much more.

This lesson includes the following sections:

Throughout the lessons, you should already have begun to take advantage of the debugging features of Visual Studio to run and debug your programs. The ability to use a visual debugging tool is one of the primary features of modern integrated development environments (IDEs). We introduced some of the basic debugging techniques earlier, and we will review them again as we add to the list of debugging features you can use in Studio.

Errors may exist in our software at different levels. Errors that prevent the program from compiling, which therefore prevent the program from running, are called compile-time errors. Even if your program compiles, it still may not run correctly. Errors that occur when your program runs are called runtime errors. Finally, if your program compiles and runs, but the results you get from your program are incorrect, the cause may be logic errors. You've undoubtedly seen compile-time errors before, unless you've managed to make no mistakes in your code. If so, congratulations! When you encounter a compile-time error, Studio presents you with an alert that helps find the line of code that contains the error, and hints as to what is wrong and possibly how to resolve the error. For this lesson, we'll focus on using the Studio debugging features at runtime. These features help resolve runtime and logic errors.

As the word implies, debugging is removing "bugs," or defects, from your software, but with Studio, you can use the same tools you would use for debugging to learn more about the C# language, and how your code behaves. The Studio debugging tools enable you to step through your code, evaluate variables, and so much more.

A Sample Debugging Program

For this lesson, we'll use a simple program to explore the debugging features of Studio. Let's get started.

Select File | New | Project, change the project Name to Debugging, and click OK. Locate the entry for Form1.cs and change it to Debugging.cs. Click the Form1 Form title bar, find the Text property in the Properties Window, and change it to Debugging. Click to save your changes.

Now let's add the controls we'll need.

Modify the Debugging Form by adding the controls listed below. Change each control's Name property to match the Name Property column, and each Text property to match the Text Property column in the table. Arrange the controls like in the image below.

ObjectName PropertyText Property
LabelenterTextLabelEnter Text:
TextBoxdataTextBox 
LabelletterCountLabelLetter Count:
LabelletterCountValueLabel0
LabelwordCountLabelWord Count:
LabelwordCountValueLabel0
ButtoncountButtonCount
ButtoncloseButtonClose

Click to save your changes. Next, let's add all of the event handlers we'll need.

Double-click each Button control to add the click events. Click .

ControlEventEvent Name
countButtonClickcountButton_Click
closeButtonClickcloseButton_Click

Next, let's add a couple of methods and code to the event handlers.

Select the Debugging.cs Form Code Editor and modify the code as shown below.

Debugging.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace Debugging
{
    public partial class Debugging : Form
    {
        public Debugging()
        {
            InitializeComponent();
        }
        
        private void countButton_Click(object sender, EventArgs e)
        {
            letterCountValueLabel.Text = countLetters(dataTextBox.Text).ToString();
            wordCountValueLabel.Text = countWords(dataTextBox.Text).ToString();
        }
        
        private void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        
        private int countWords(string textData)
        {
            int wordCount = 0;
            wordCount = Regex.Matches(textData, @"[A-Za-z0-9]+").Count;
            return wordCount;
        }
        
        private int countLetters(string textData)
        {
            int letterCount = 0;
            letterCount = Regex.Matches(textData, @"[A-Za-z]").Count;
            return letterCount;
        }
    }
}

Click and to save and run the program. Enter a sentence of a few words, and include some numerals, such as "the quick brown fox 9," and click Count. You should see something like this:

Let's discuss the code.

OBSERVE: Debugging.cs
using System;
.
.
.
using System.Text.RegularExpressions;

namespace Debugging
{
    public partial class Debugging : Form
    {
        .
        .
        .
        private void countButton_Click(object sender, EventArgs e)
        {
            letterCountValueLabel.Text = countLetters(dataTextBox.Text).ToString();
            wordCountValueLabel.Text = countWords(dataTextBox.Text).ToString();
        }
        .
        .
        .
        private int countWords(string textData)
        {
            int wordCount = 0;
            wordCount = Regex.Matches(textData, @"[A-Za-z0-9]+").Count;
            return wordCount;
        }
        
        private int countLetters(string textData)
        {
            int letterCount = 0;
            letterCount = Regex.Matches(textData, @"[A-Za-z]").Count;
            return letterCount;
        }
    }
}

This sample program counts the number of letters and words in a user-entered text string. Letters include any letter in the English alphabet, whether uppercase or lowercase. When you clicked the Count Button, the countButton_Click event handler "fired," calling the countLetters and countWords methods. Each of these methods returns an int value that we use to set the appropriate Label.

We introduced the Regex class that requires the new using statement. Regex supports regular expressions. A regular expression is a pattern-finding and replacing notation that's been around for many years. You can search online for more information on how to create a regular expression. Microsoft also provides a nice overview at Regular Expressions. We'll use Regex to remind you of a handy debugging feature you should have seen before: Intellisense Quick Info. With Quick Info, you can hover your mouse pointer over any C# identifier and see additional information. Below, we've hovered over Regex:

Note that we're using the class name Regex without creating an object instance, so Regex must be a static class.

You may also have noticed the @ symbol before the second Regex parameter, which is the actual regular expression. The @ symbol when used before string literals effectively "escapes" the text within the string literal. Escaping is using a special symbol before a character to change the meaning of the character. We've seen special escape chararacters already: \n, for carriage return; and perhaps \t, for horizontal tab. The \ character is the escape character in C#, but it is also used in regular expressions, and even in Windows file path names. If we want to use the \ as a backslash, and not get an error, we would have to put two back slashes, \\, to get the single slash we want—effectively, escaping the escape. Or, we can place the @ symbol before the string literal.

NoteThe @ symbol is used for other purposes in C# that we'll cover as those topics are introduced in the lessons.
Breakpoints, Expression Evaluation, and Watches

In the Visual Code Editor window, we can add one or more breakpoints to our code. A breakpoint is exactly what the name implies: a point in your source code where execution will stop, or break. Let's add a breakpoint, then execute our code in debug mode and stop at the breakpoint.

Select the Debugging.cs Form Code Editor, and scroll the window so that you can see the countButton_Click event handler. Move your mouse pointer to the left of the line that sets the letterCountValueLabel.Text, which is the first line in the event handler. Keep moving your mouse to the left of the outline lines, and the change bars, until you get to a vertical section that spans the entire Code Editor. Click in this area until you get a red circle that is parallel to the letterCountValueLabel.Text line of code, and highlights the line of code in red. (If you place the red circle next to the wrong line, click the red circle again to remove it.)

NoteWhen you run a program, this lesson text disappears while the program takes control of Visual Studio. The lesson text will reappear when the program ends. However, when the program pauses at your breakpoint, you won't be able to see the lesson text. To bring back the lesson text, select Windows | C# Part 2. Then, right-click the C# Part 2 tab and select Move to previous tab group.

Click the Start Debugging button to run the program. Type My dog is brown and click Count. The program stops executing, with Studio highlighting the breakpoint in yellow:

While the program is paused at a breakpoint, several debugging tools are added to the toolbar:

Especially note the Continue button:

Click that button when you're ready to continue running the program.

We're not limited to simply pausing our code whenever a breakpoint is encountered. Let's get a list of breakpoint options.

With our code paused at the first breakpoint, right-click the red breakpoint circle:

As you can see, we can delete the breakpoint, which can also be accomplished by simply clicking the red breakpoint circle again, as the breakpoints are effectively toggles. We can also disable a breakpoint, which is convenient in keeping a breakpoint for later use, but skipping it when it isn't needed. The other breakpoint options each bring up a dialog box. Each of these breakpoint options are explained below.

NoteWhen you save a file in Studio, you also save the breakpoint information.

Breakpoint OptionDialogDescription
LocationFile BreakpointProvides exact information about breakpoint.
ConditionBreakpoint ConditionSet breakpoint trigger conditions.
Hit CountBreakpoint Hit CountSet breakpoint trigger hit criteria.
FilterBreakpoint FilterSet advanced breakpoint trigger conditions.
When HitWhen Breakpoint Is HitSet advanced behavior when breakpoint is triggered.
Edit LabelsEdit Breakpoint LabelsSet a label (name) to a breakpoint.
ExportBreakpoint Save AsSave breakpoint information to an external file.

With small programs, most of these advanced breakpoint options are unnecessary, but with larger programs, it's very common to set advanced breakpoint options to only break under certain circumstances. Feel free to experiment with any of these advanced options, such as the hit count option.

With the program paused at this first breakpoint, we can perform a number of useful debugging, and learning, tasks, such as variable, field, and property evaluation. Let's try it!

Hover over the dataTextBox.Text identifier in the yellow highlighted code. Make sure you place the mouse pointer over the Text property:

That's pretty useful to be able to hover over a property and see the value. But you're not limited to just properties; you can also view the TextBox object.

Hover over the dataTextBox identifier in the yellow highlighted code. Make sure you place the mouse pointer over the dataTextBox object:

You'll notice that with the TextBox object, you have an expansion control, the plus symbol, to expand the popup to display other information about the identifier you've selected.

Hover over the dataTextBox identifier in the yellow highlighted code. Make sure you place the mouse pointer over the dataTextBox object. Click the expansion plus symbol to see expanded information:

We're mostly interested in the Text property of the TextBox, but in the expanded view, you can see all of the fields and properties for the TextBox object. You should note that at the bottom of the expanded view is a black down arrow that serves as a scrolling arrow to see more of the fields or properties.

NoteIf you do not see the plus character to view the expanded information box, you probably hovered over just the Text identifier. Intellisense is context-sensitive, showing the most limited information it can provide based on what you're hovering over. To see the expanded view option, you have to hover over the TextBox identifier, dataTextBox.

In the popup that appears when you hover over an identifier, you'll notice that there is a magnifying glass button, and a dropdown arrow next to the magnifying glass. The magnifying glass, when clicked, will display one of three data Visualizers: a Text Visualizer, an XML Visualizer, or an HTML Visualizer. By default, the Text Visualizer is selected, and will be displayed. A Visualizer is a very convenient tool for seeing data in a different format, or when the data is lengthy. Let's bring up the Text Visualizer.

Hover over the dataTextBox identifier in the yellow highlighted code. Make sure you place the mouse pointer over the dataTextBox object. Click the magnifying glass symbol to see the Text Visualizer:

Click Close. You can change the selected Visualizer by clicking the dropdown arrow, and selecting the desired Visualizer:

You still have more options. You can also right-click on the popup, and see a menu option to copy or edit the value of the identifier you're evaluating, and a number of other options. Let's bring up the popup menu first.

Hover over the dataTextBox.Text identifier in the yellow highlighted code. Make sure you place the mouse pointer over the Text property. Right-click the popup that appears to bring up a new popup menu.

Below are descriptions of the Copy options.

Copy ChoiceValue
CopydataTextBox.Text = "My dog is brown."
Copy ExpressiondataTextBox.Text
Copy Value"My dog is brown."

Another option from the popup menu is Add Watch, which will be our next topic, after we explore moving forward in our code. Once stopped at a breakpoint, when you're ready to move forward, you have a number of options; the most common ones are:

Move OptionDescription
Step OverExecute the current statement, but do not step into any code that might be accessed.
Step IntoExecute the current statement, stepping into any code that is accessed.
Run To CursorPlace mouse pointer on another line of code, and execute until that line of code is encountered.
ContinueResume normal execution, breaking at next breakpoint, if any.
StopStop executing the program.

You should still be at the first break point. Let's use the Step Into option.

Select Debug | Step Into, or locate and click the Step Into button on the Studio toolbar.

NoteThe hotkeys in Visual Studio may change.

After selecting the Step Into debug option, you are in the countLetters method. Once you've stepped into the code you want to examine, you typically switch to using the Step Over method, to prevent stepping into other code, unless you want to continue to step further and further into your code. In our case, the countLetters method is the final level we want to step into.

Select Debug | Step Over, or find and click the Step Over button on the Studio toolbar. Continue to select the Step Over option until Studio highlights in yellow the line of code that contains the Regex code.


Now, let's add the Watch on letterCount. Rather than use the method we've used before to add a Watch variable, we'll use a much simpler method.

Right-click on the letterCount variable in the countLetters method. From the popup menu, select Add Watch.

Once you've added the Watch, you should see the Watch 1 tab, with the letterCount variable.

NoteIf for some reason you're unable to see the Watch 1 tab, you may have to make it visible using Debug | Windows | Watch | Watch 1.

While you can add as many Watch items as you'd like, Studio already has an easy way to see variables that are local to the current scope in the Locals Window.

Locate and select the Locals tab (if the Locals tab is not visible, select Debug | Windows | Locals).


We've looked at the Locals and Watch 1 tab, so you might want to look at what other tabs are available while you're debugging a C# program. Some of the tabs aren't appropriate to discuss in this lesson, but there are three other tabs you will find pretty useful, so you should be familiar with them.

The first is the Output tab, which we've used before. Whenever your program generates Console output, such as with a System.Console.WriteLine statement, the output appears in the Output tab.

The second useful tab is the Call Stack tab. This tab displays the stack path the code has followed to get to the current line. Only those lines of code that called to a different location in the code that jumped into a new scope, such as with a method call, are shown on the Call Stack tab. You can double-click any entry, and you'll be taken to that location in the code.

NoteYou will probably notice that certain entries in the Call Stack appear light grey, or greyed out. These lines of code represent calls into other programming code, such as the .NET framework, that are not code within your project. You can try to jump to these lines of code, but unless you have the source code installed, you will receive a message that no source code is available.

The third useful tab is the Immediate tab. This tab is a very interesting tab, as you can type in C# code to evaluate expressions, display the results of expression results, and even change the value of identifiers. To display identifier or expression results, the Immediate window supports a shortcut symbol, the question mark (?), for output. Here are some examples of what you can do in the Immediate Window:

From the sample output, you can see we display the current value of letterCount, then change the value of letterCount to 13, and confirm the value change by again displaying the current value, then displaying the result of adding 3 to the value of letterCount, and then displaying the current value, which was unchanged, as the previous statement had added 3 to value without changing the value. The Immediate window can be a very powerful tool!

Before finishing this section, let's return to Watch variables once again for a few final features. One feature is QuickWatch, a quick way to bring up information on an identifier, and Pin to Source, a great way to have a Watch variable appear next to the line of code. Both of these options are available when you right-click an identifier. Go ahead, try it!

Right-click the letterCount variable, and select QuickWatch. Close the QuickWatch dialog box. Right-click the letterCount variable again, and select Pin to Source. Then, hover the mouse pointer over the pinned letterCount watch, and select the X option to remove it.


Click the continue button to let the program continue, and click Close to end the program. You can close the window we opened earlier now too.

So, that concludes our study of the debugging features in Studio. No, we haven't covered all of them, but the ones we did cover should help you feel more confident in stepping through your code, and letting Studio help you learn more about the C# language!

Before you move on to the next lesson, do your homework! Right-click in the window where this lesson text appears and select Back. Then select Quiz for this lesson in the syllabus and answer the quiz questions. When you finish the quiz questions, click HAND IT IN at the bottom of that window. Then do the same with the Project(s) for the lesson. Your instructor will grade your quiz(zes) and project(s) and provide guidance if needed.