Debugging is important, and it's often useful to be able to inspect the state of objects in the debugger. However sometimes you're working with 3rd party types that don't have any debugging capabilities, so you can't see their internal state easily. In this blog post we will have a look on how to equip 3rd party types with debugging capabilities.
DebuggerDisplayAttribute
to the rescue
The DebuggerDisplayAttribute
is a very useful attribute that allows you to specify how an object should be displayed in the debugger. "Equipping" your own types as such:
[DebuggerDisplay("Name = {Name}, Age = {Age}")]
public class Person
{
public required string Name { get; set; }
public required int Age { get; set; }
}
var person = new Person { Name = "John", Age = 42 };
This will make the debugger display the Person
object as Name = John, Age = 42
. Cool, cool, cool. But what if you're working with a 3rd party type where you can't easily add the DebuggerDisplayAttribute
? Well, what if I tell you, that you can?
Equipping 3rd party types with DebuggerDisplayAttribute
There is a lesser known property called Target
which defines, which type the DebuggerDisplayAttribute
should be applied to. We can use this in combination with the assembly
attribute to equip any type with debugging capabilities. For the sake of keeping it easy, I will equip the Task
type even though it already has debugging capabilities.
[assembly: DebuggerDisplay("Is Task finished: {IsCompleted}", Target = typeof(Task))]
var task = Task.Delay(100_000);
await task;
Now, hovering over the task
object will result into:
There are some "natural" downsides to this approach:
- You can only use public types or interfaces for obvious reasons.
- It might be not obvious where the debugging information is coming from. Especially if you have a deep dependency graph and someone in the middle is equipping a type with debugging capabilities.