March 2, 2021
Hot Topics:

Tip: Detecting Defects in C# Programs

  • By Steve Porter
  • Send Email »
  • More Articles »

During Quality Assurance (QA) reviews and maintenance cycles I have come across defects that are difficult to diagnose and reproduce the exact set of events under which the abnormality is occurring. Solving the issues usually requires additional information. This is where the System.Diagnostics Debug and Debugger classes are tools you can use to provide targeted information.

Using System.Diagnostics.Debug

The System.Diagnostics.Debug class provides method calls and properties that can provide formatted conditional information. Code containing the Debug class can remain in release code as it is not compiled into IL unless the DEBUG compilation attribute is set and thus will have no effect or cause code bloat. Useful methods include:

Assert Checks for a specific condition and displays an error message if that condition is false.
Equals Determines whether the specified Object is equal to the current Object.
Indent Increases the current IndentLevel by one.
Unindent Decreases the current IndentLevel by one.
WriteLineIf Write specific information to the attached trace listeners if a specific condition is true

The Debug class is often used to prevent code defects by verifying logic during code development and maintenance. The following example verifies the input parameter is within a valid range, if it is not, Assert will output a message.

Debug.Assert(inputValue < byte.MaxValue, "Value is out of range");

Using System.Diagnostics.Debugger

The System.Diagnostics.Debugger class communicates with an attached debugger. When an assembly is executed within an attached debugger, the Debugger.Break method will stop execution as if the IDE had instituted a breakpoint. The debugger can then be used normally to investigate assembly state.

Benefits of the Debug and Debugger Classes

Together, these two classes, Debug and Debugger, can assist in diagnosing complicated data related issues or issues that occur intermittently. The following code not only produces generic formatted output, but also outputs information related to a specific item and stops code execution when invalid data is encountered so that the member variables and stacktrace can be examined.

    class Program 
        static void Main(string[] args) 
            // Add example data 
 personList = new List(); 
            personList.Add(new Person { FirstName = "Joe", LastName = "Smith" }); 
            personList.Add(new Person { FirstName = "Mike", LastName = "Jones" }); 
            personList.Add(new Person { FirstName = "Sarah", LastName = "Douglas" }); 
            Debug.WriteLine("Begin Iterating People"); 
            // Itterate, output and examine people
            for (int personIdx = 0; personIdx < personList.Count(); personIdx++) 
                Debug.WriteLine(string.Format("Person {0}", personIdx.ToString())); 
                // if a portion of the persons name is null, use the debugger to examine variables
                if (Debug.Equals(personList[personIdx].FirstName, null) || Debug.Equals(personList[personIdx].LastName, null)) 
                Debug.WriteLine(string.Format("Firstname: {0}", personList[personIdx].FirstName)); 
                Debug.WriteLine(string.Format("Lastname: {0}", personList[personIdx].LastName)); 
                Debug.WriteLineIf(personList[personIdx].FirstName == "Mike", "Mike is Found!"); 
            Debug.WriteLine("End Iterating People");            
    public class Person 
        public string FirstName { get; set; } 
        public string LastName { get; set; } 

This code produces the following formatted output in the output window:

    Begin Iterating People 
    Person 0 
        Firstname: Joe 
        Lastname: Smith 
    Person 1 
        Firstname: Mike 
        Lastname: Jones 
        Mike is Found! 
    Person 2 
        Firstname: Sarah 
        Lastname: Douglas
End Iterating People 

If data is invalid, for example in this case changing a FirstName of to null, the debugger will break at the point specified (see Figure 1)

Figure 1

This methodology can be used when the result of a defect is known but it is not known how to routinely reproduce the issue. If a team of developers were executing this code, any developer could trigger the conditions that would stop code execution at that point. The state of the assembly could then be examined. This additional information could be the difference between taking minutes to solve an intermittent problem to days attempting to recreate it under a known set of circumstances.

In future additional tools in the System.Diagnostics namespace will be examined that assist in diagnosing data and performance issues found in released software by utilizing the Trace and TraceListener classes.

# # #

This article was originally published on May 4, 2009

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date