Daily Knowledge Drop
The format of how classes are displayed in the debugger can be customized
, using a numer of different methods.
Sample
All the samples below use an instance of the following simple entity class:
// class definition
public class Song
{
public int Id { get; set; }
public string Name { get; set; }
public string Artist { get; set; }
public int YearReleased { get; set; }
public int LengthInSeconds { get; set; }
}
// instance of the class
var song = new Song
{
Id = 1,
Name = "Everlong",
Artist = "Foo Fighters",
LengthInSeconds = 250,
YearReleased = 1997
};
Default Display
By default, the output of a class in the debugger uses the ToString method on a class. The default for this method on a class is the class namespace and name.
The output in the Watch Window as well as when hovering the cursor over the instance:
ToString override
The first approach in customizing the output is to override the ToString
method on the class:
public class Song
{
//... existing class properties omitted
// ToString method overridden and customized
public override string ToString()
{
return $"Song `{Name}` by '{Artist} released " +
$"in '{YearReleased}' and is '{LengthInSeconds}' seconds long";
}
}
This overridden ToString method is now used:
DebuggerDisplay attribute
In some use-cases, it might not be possible to use the ToString method, as it might be used in the functionality of the application in a specific format, and a different format is required for the debugger.
The next approach uses the DebuggerDisplay
attribute - this is used to decorate the class with the format of the debugger display.
[DebuggerDisplay("{Name} by {Artist}")]
public class Song
{
//... existing class properties omitted
public override string ToString()
{
return $"Song `{Name}` by '{Artist} released " +
$"in '{YearReleased}' and is '{LengthInSeconds}' seconds long";
}
}
The display in the debugger now uses the DebuggerDisplay format, while explicitly using the ToString method will return the ToString method format.
External classes
A 3rd party external class can also be targeted by the attribute.
Assume Song is now a external 3rd party class (which cannot be modified), and has no DebuggerDisplay
attribute:
public class Song
{
//... existing class properties omitted
public override string ToString()
{
return $"Song `{Name}` by '{Artist} released " +
$"in '{YearReleased}' and is '{LengthInSeconds}' seconds long";
}
}
In the Program.cs startup file, the 'DebuggerDisplay` attribute is added with a specified Target:
[assembly: DebuggerDisplay("External: {Name} by {Artist}", Target = typeof(Song))]
var song = new Song
{
Id = 1,
Name = "Everlong",
Artist = "Foo Fighters",
LengthInSeconds = 250,
YearReleased = 1997
};
Console.WriteLine(song);
The format specified by the DebuggerDisplay
outside the class, is now used:
Notes
We've looked at a few useful ways in which the Visual Studio developer experience can be enhanced to improve the quality of life and productivity while working with a solution.
(The same might be experienced in Visual Studio Code and Rider, but it was not tested as part of this post)
References
Daily Drop 26: 08-03-2022
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.