Debugging your .NET application more easily

 
 
  • Gérald Barré

As a programmer, you often have to debug your code, or the code written by a coworker. I don't like debugging, but as you know:

If debugging is the process of removing bugs, then programming must be the process of putting them in.

Unless you are an extraordinary developer, you'll need to debug your code. Visual Studio provides great tools to help you with this task. The main features are breakpoints, step by step execution, and viewing the value of the variables:

By default, the debugger doesn't always show useful values. In the previous screenshot, you cannot quickly distinguish the 2 customer instances. Let's see how to improve that and thus, reduce the time needed to debug your application!

#Override the ToString method

By default, the value of the ToString method is shown. So, the first way to change the display value is to override the ToString method and return something more useful:

C#
public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Order> Orders { get; } = new List<Order>();

    public override string ToString()
    {
        return $"{FirstName} {LastName}";
    }
}

#Use the DebuggerDisplay attribute

When you don't want to override the ToString method just for debugging purposes, you can use the DebuggerDisplay attribute. The value of the attribute uses a format similar to the syntax introduced in C# 6 with string interpolation. However, the text between brackets are expressions to be evaluated by the debugger engine. So, an expression can be a property name or a more complex expression such as {Count > 0 ? Count : 0}.

C#
[DebuggerDisplay("{Id} - {FullName} ({Orders.Count} orders)")]
public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Order> Orders { get; } = new List<Order>();

    public string FullName => $"{FirstName} {LastName}";
}

Evaluating an expression by the debugger is expensive, so you should not have too many expressions in the display value. Instead, you can create a private property in your class, and use only this property in the DebuggerDisplay attribute.

C#
[DebuggerDisplay("{DebuggerDisplay,nq}")] // nq means no quote
public class Customer
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DebuggerDisplay => $"{Id} - {FullName} ({Orders.Count} orders)";
}

I use the nq format to prevent Visual Studio from adding quotes around the value. You'll find valid formats in the documentation.

Note that you can also add the attribute to a type you don't own by adding the attribute at the assembly level and by specifying the Target property:

C#
[assembly: DebuggerDisplay("{Host}", Target = typeof(Uri))]

#Hide code to the debugger

You can annotate your code with some attributes to change the behavior of the debugger when you run step by step. For instance, you don't want the debugger to step into generated code. In this case, you can add one of the following attributes:

C#
static void Main()
{
    GeneratedMethod(); // Step into...
}

[DebuggerNonUserCode]
private static void GeneratedMethod() // show as External Code in the call stack
{ // do not step here
    MyCode();
}

private static void MyCode()
{ // ... step here
}

The GeneratedMethod method is not visible in the call stack:

Call Stack with DebuggerNonUserCodeAttributeCall Stack with DebuggerNonUserCodeAttribute

#Use the DebuggerTypeProxy attribute

The DebuggerTypeProxyAttribute attribute is used to specify a display proxy for a type, allowing a developer to tailor the view for the type. If the attribute is found, the expression evaluator substitutes the display proxy type for the type the attribute is applied to. This is useful when you want to expose properties that are not in the original type.

C#
[DebuggerTypeProxy(typeof(SampleDebugView))]
public class Sample
{
    public string Name { get; set; }

    private class SampleDebugView
    {
        private readonly Sample _sample;

        public SampleDebugView(Sample sample)
        {
            _sample = sample;
        }

        public string Name => _sample.Name;
        public int NameLength => _sample.Name.Length;

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public char[] NameCharacters => _sample.Name.ToCharArray();
    }
}

You can check real examples in the .NET framework: https://github.com/dotnet/runtime/search?q=DebuggerTypeProxy&type=Code

#Conclusion

The Visual Studio debugger is very great. It allows you to quickly debug your code by using breakpoints, viewing the value of the variables, and more. You can customize it by adding some attributes to your code. These attributes should help you in reducing the time needed to debug your application.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub