Learn .NET  

Improve Debugging in .NET Using the DebuggerDisplay Attribute

Debugging is a crucial part of software development, and when you're working with complex object models in .NET, navigating through variables during a debugging session can become overwhelming. Thankfully, .NET provides a handy attribute, [DebuggerDisplay], to simplify and enhance the debugging experience.

In this article, we’ll explore what [DebuggerDisplay] does, why it’s useful, and how you can use it effectively in your .NET applications.

Why Use [DebuggerDisplay]?

By default, debugging a class like this:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

The debugger shows something like:

{Namespace.Product}

Which doesn’t tell you much until you expand the object.

But with [DebuggerDisplay]:

[DebuggerDisplay("Id = {Id}, Name = {Name}, Price = {Price}")]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Now you’ll see:

Id = 101, Name = Laptop, Price = 1200.00

Much better, right? Let's explore some more details, how to use with examples.

How to Use [DebuggerDisplay]

Basic Syntax:

[DebuggerDisplay("Property1 = {Property1}, Property2 = {Property2}")]
public class MyClass
{
    public string Property1 { get; set; }
    public int Property2 { get; set; }
}

The {} syntax tells the debugger to evaluate the expression during runtime.

Using Private Methods or Properties

You can also reference private members, or even a private helper method:

[DebuggerDisplay("{GetDebuggerDisplay(),nq}")]
public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    private string GetDebuggerDisplay()
    {
        return $"{FirstName} {LastName}";
    }
}

The nq (no quotes) modifier strips surrounding quotes for string results.

Conditional Debug Display

This is needed when we need more control.

[DebuggerDisplay("Status = {Status}, Active = {IsActive}")]
public class UserSession
{
    public string Status => LastLogin < DateTime.UtcNow.AddDays(-7) ? "Inactive" : "Active";
    public bool IsActive { get; set; }
    public DateTime LastLogin { get; set; }
}

You can dynamically compute values based on object state.

What Not to Do

  • Avoid calling complex logic or external resources in debugger expressions.

  • Don’t use [DebuggerDisplay] on types you don’t own (e.g., framework types).

  • Don’t overcomplicate the expression — it’s for quick inspection, not full logic.

DebuggerDisplay vs. ToString()

ToString() is for runtime string representation (e.g., logs, UI), while [DebuggerDisplay] is for design-time debugging only.

Use both — but for their own purposes.

Conclusion

The [DebuggerDisplay] attribute is a small but powerful feature that can significantly improve your productivity while debugging. By customizing what you see in your debugger, you spend less time digging and more time solving real problems.

So the next time you're building a complex class or DTO, take a few seconds to add [DebuggerDisplay] — your future debugging self will thank you!