Exploring the .NET CoreFX Part 3: Making Methods Debugger-Friendly
Exploring the .NET CoreFX .net core csharp system.collections.immutable
Published: 2014-11-19
Exploring the .NET CoreFX Part 3: Making Methods Debugger-Friendly

This is part 3/17 of my Exploring the .NET CoreFX series.

System.Collections.Immutable uses a number of attributes to make it more debugger-friendly. Here are the key attributes:

DebuggerStepThrough

Occasionally a method is so simple that it doesn’t make sense to have the debugger step into it. The System.Diagnostics.DebuggerStepThroughAttribute instructs the debugger to step through the code instead of stepping into the code.

Here is an example from System.Collections.Immutable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
internal static class Requires
{
    [DebuggerStepThrough]
    public static void Range(bool condition, string parameterName, string message = null)
    {
        if (!condition)
        {
            FailRange(parameterName, message);
        }
    }
}

DebuggerBrowsable

The System.Diagnostics.DebuggerBrowsableAttribute determines if and how a member is displayed in the debugger variable windows.

Here are a few examples from System.Collections.Immutable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public partial struct ImmutableArray<T>: IReadOnlyList<T>, IList<T>, IEquatable<ImmutableArray<T>>, IImmutableList<T>, IList, IImmutableArray, IStructuralComparable, IStructuralEquatable
{
    ...

    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
    internal T[] array;

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    bool ICollection<T>.IsReadOnly
    {
        get { return true; }
    }

DebuggerDisplay

The System.Diagnostics.DebuggerDisplayAttribute controls how a class or field is displayed in the debugger variable windows. For example, if you were writing a class to represent a complex number, you could use the DebuggerDisplay attribute to render the complex number as (a, b) or even a + bi.

Here are a few examples from System.Collections.Immutable:

1
2
3
4
5
[DebuggerDisplay("Count = {stack != null ? stack.Count : 0}")]
internal static class AllocFreeConcurrentStack<T>
{
    ...
}
1
2
3
4
5
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public partial struct ImmutableArray<T> : IReadOnlyList<T>, IList<T>, IEquatable<ImmutableArray<T>>, IImmutableList<T>, IList, IImmutableArray, IStructuralComparable, IStructuralEquatable
{
    ...
}

DebuggerTypeProxy

The System.Diagnostics.DebuggerTypeProxyAttribute allows the developer to specify a display proxy for a type, allowing the developer to completely tailor the view for the type.

Here is an example from System.Collections.Immutable:

1
2
3
4
5
6
public partial struct ImmutableArray<T>
{
    [DebuggerTypeProxy(typeof(ImmutableArray<>.Builder.DebuggerProxy))]
    public sealed class Builder : IList<T>, IReadOnlyList<T>
    {
        ....

Recommendations

  1. Judiciously use DebuggerStepThrough, DebuggerBrowsable, DebuggerDisplay, and DebuggerTypeProxy to make your code more debugger-friendly.