Microsoft & .NET Visual C# Tip: Detecting Defects in C# Programs

Tip: Detecting Defects in C# Programs

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
List 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”);
Debug.Indent();

// Itterate, output and examine people
for (int personIdx = 0; personIdx < personList.Count(); personIdx++)
{
Debug.WriteLine(string.Format(“Person {0}”, personIdx.ToString()));
Debug.Indent();

// 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))
{
Debugger.Break();
}

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.Unindent();
}

Debug.Unindent();
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.


# # #

Latest Posts

Related Stories