Crashing the Visual Studio debugger using DebuggerDisplay

If you already know and use the DebuggerDisplay you can fast-forward to the evil stuff. Otherwise, keep reading to learn a new useful tool and also how not to use it.

Introduction to DebuggerDisplay

Let’s start with a quick demonstration of when and how DebuggerDisplay is useful. Let’s say you have some code like this:

public class Person
{
    public string Name { get; set; }
}

public class Employee : Person
{
    public string Department { get; set; }
}

Now, let’s say that you have a variable in your code that references an IEnumerable. If you watch that value using the debugger, it can look like this:

Employee list without DebuggerDisplay

We can see that there is a sequence of Employee objects, but not much more. If we wanted to verify that there is an Employee instance with the name “Sophie Jackson” we would need to expand each object to examine its Name property which is a tedious task to say the least. This is where DebuggerDisplay can help out. By decorating the Employee class with the DebuggerDisplay attribute, we can control how the debugger will display the object:

[DebuggerDisplay("Employee [Name = {Name}, Department = {Department}]")]
public class Employee : Person
{
    public string Department { get; set; }
}

Now, if we check the value of the employees variable as above, it will instead look like this:

Employee list with DebuggerDisplay

Now it’s obviously a lot easier to find the employee called “Sophie Jackson”. Just browse through the list and you will quickly see whether that Employee instance is there or not.

More advanced usage

The debugger will evaluate the expression found in the DebuggerDisplay attribute and show the value. Can this be used to do more complex things than to get a value from a property? Yes, it can. However, I urge you to resist the temptation to do fancy stuff here. The DebuggerDisplay attribute can have unwanted side effects, as we will see further down in this article. Let’s look at an example:

[DebuggerDisplay("Employee [Name = {Name}, EmpYears = {((int)(System.DateTime.Now - EmploymentDate).TotalDays / 365)}]")]
public class Employee : Person
{
public string Department { get; set; }
public DateTime EmploymentDate { get; set; }
}

Again, watching the employees variable in the debugger:

Employee list with DebuggerDisplay expression

You can see how each object is presented with a number that is calculated based on the difference between the current date and EmploymentDate, converted to years and cast to an int.

Now, while this is a very useful feature, it should be used with care. If we consume the class used in this example from code written in VB.NET this is what we get:

VB.NET cannot interpret C# expression

As you can see, the debugger now fails to evaluate the expression calculating the number of years. The reason is explained in the documentation:

Expressions are evaluated by the expression evaluator of the language of the current stack frame and not by the evaluator of the language in which the expression was written. This can cause unpredictable results when the languages are different.

So instead of the evaluated expression, you get an error message. The same happens if you for instance have a typo in the property name:

Employee list with misspelled property

As we can see, the DebuggerDisplay attribute is very useful, but should be used to evaluate very simple and “cheap” values. Personally I only tend to use it to fetch values from property getters that just returns the value from a backing field with no other logic being involved. Above all, make sure to not have DebuggerDisplay invoke any code that till mutate any state…

How DebuggerDisplay may crash your debugger

As we have seen from the above examples it’s not very hard to make the debugger fail to evaluate the expression in a DebuggerDisplay attribute, but it does so in a nice and forgiving manner: it simply replaces the value placeholder with an error message instead of the evaluated expression. However, it is possible (even simple) to write an expression that instead will make you see this:

Employee list with crashed debugger

Now, that is not nice. I actually experience this in a project where this error started to appear among the developers and where we at first couldn’t identify what caused the environment to crash, since there (at first) were no obvious pattern of where the crash happened. After a while one of the team members found the offender. It was a DebuggerDisplay attribute crafted like this:

[DebuggerDisplay("Employee [Name = {base.Name}, Department = {Department}]")]
public class Employee : Person
{
    public string Department { get; set; }
    public DateTime EmploymentDate { get; set; }
}

Note the base.Name construct. This is what caused the debugger to crash. I found this somewhat surprising (perhaps even to be considered a bug in the debugger?), especially since it works well to use the construct this.Name.