Retour à l'aperçu

Increase your debugging skills with DebuggerDisplay

Par Ruben Verheyen

.NET

Feb 2020

In Visual Studio, when debugging, the Watch-window uses the ToString()-method of the item you want to explore. When watching a complex type like a class, this might not give you much valuable info. The DebuggerDisplayAttribute will help you show useful information in debug mode. Does this scenario sound familiar to you?

You fetch some data collection from your backend. While debugging, you want to take a peek at the items and then this happens:

var persons = _repository.GetPersons();

It’s not possible to inspect the items at a glimpse of an eye. You’ll have to click every item to open its properties. It totally makes sense that Visual Studio does not show any details, because Visual Studio is unaware as to what info might be relevant for your debugging needs.

Well, today is your lucky day, because you are about to discover the DebuggerDisplayAttribute!

Why do we need a designated attribute? Can’t we just override ToString() to achieve that?

Well, you could override ToString(), but ToString() is meant as the default display string.
DebuggerDisplay is meant for debugging. It’s very likely that you might want to have more details for debugging purposes than you want in your ToString(). You can use them both but remember that DisplayDebugger will have precedence by default. This can be overridden in the Visual Studio options under Tools>Options>Debugging and select ‘Show raw structure of objects in variables windows’.

How do we start?     

We’ll decorate our class with the DebuggerDisplay attribute:

[DebuggerDisplay("{FirstName} {LastName}")]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    // ...
}

When we debug our code again, Visual Studio now knows what it needs to display:

As you can see, the property LastName is null and Visual Studio knows how to display that.

[DebuggerDisplay("{FirstName,nq} {LastName}")]

Expressions

The DebuggerDisplayAttribute accepts expressions. You can compare it to interpolation in Angular

[DebuggerDisplay(“{ 20 + 22 }”)] will display as 42.

In our example, we might want to display the name in uppercase.

[DebuggerDisplay("{FirstName.ToUpper()} {LastName.ToUpper()}")]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    // ...
}

Visual Studio shows us FirstName in uppercase as expected.
LastName however, is shown as the famous error “Object reference not set to an instance of an object” but it does not crash our application.

Be careful

Expressions can be very useful but can come at a cost.

Evaluating the expressions can be a costly operation because the expression will be evaluated every time it is displayed. For complex expressions and large lists, this will slow your debugging performance significantly.

Another reason to avoid expressions is that expressions can change the state of your application at debug time, making it hard to evaluate any bugs.

[DebuggerDisplay("{FirstName,nq} {LastName} {ShoeSize = 100}")]

will set every property ShoeSize to 100 when stopping at a break point after class instantiation.

var alice = new Person {FirstName = "Alice", ShoeSize = 38}; Console.WriteLine(alice.ShoeSize);

would simply display 38 if ran without debugging. But, as soon as you break after instantiation of alice it will display 100.

Good practice is to create a private property that performs the operation and returns a string with the computed value. This private property is then used to display in the DebuggerDisplay attribute.

[DebuggerDisplay("{DebuggerDisplay}")]
public class Person
{
    public Address Address { get; set; }

    private string DebuggerDisplay
    {
        get
        {
            return string.Format("{0} {1}", Address == null ? "Address is null" : Address.Street, 20+22);
        }
    }
}

Enjoy the power of the DebuggerDisplay attribute and happy debugging!

Further references:

Decorator Pattern Thumb

Par Paul Karam

Mar 2025

Decorator Pattern

One of the biggest challenges in our daily job is keeping our code clean, easy to read, extendable, and understandable. It's a difficult task, but it becomes ...

Strong Under Pressure: resilient HTTP clients Thumb

Par Michiel Mijnhardt

Nov 2024

Strong Under Pressure: resilient HTTP clients

Building resilient applications is crucial, and part of that resiliency is making sure your applications outgoing http requests are covered. The .NET go to ...

An introduction to NSwag Thumb

Par Karel Verhulst

Aug 2024

An introduction to NSwag

In the world of modern web development, API's play a crucial role in enabling communication between different software systems. The process of creating, ...

Cache primary btn default asset Cache primary btn hover asset Cache white btn default asset Cache white btn hover asset