Debugger Attributes

There’s several debugging types of attributes I use fairly regularily, such as DebuggerStepThrough and DebuggerDisplay, but I decided to take a look at some of the other, similar, attributes to see if I was missing anything, here’s what I found out.

Introduction

At the time of writing these are the debugging attributes I found

  • DebuggerStepThrough
  • DebuggerDisplay
  • DebuggerNonUserCode
  • DebuggerHidden
  • DebuggerBrowsable
  • DebuggerTypeProxy
  • DebuggerStepperBoundary

Before I get into the specific attributes, I will be listing the attribute targets that the attribute may be applied to, when it says an attribute may be set on a method, this also includes the setter/getter (methods) on a property. But not the property itself, this requires the AttributeTargets.Property target to be set.

DebuggerStepThrough

References

DebuggerStepThroughAttribute Class

Usage

  • Class
  • Struct
  • Constructor
  • Method

Synopsis

Let’s start with the one I used a lot in the past (on simple properties, i.e. equivalent of auto-properties). Placing a DebuggerStepThrough on any of the usage targets, will inform the debugger (in Visual Studio, not tested in Xamarin Studio as yet) to simply step through (or in debugging terms, step over) the code. In other words the debugger will not enter a method call.

This is especially useful for situations where, maybe you have simple code, such as properties which just return or set a value and this will save you stepping into this property setters or getters during a debugging session.

Example

public class MyClass
{
   private int counter;

   [DebuggerStepThrough]
   public int Increment()
   {
      return counter++;
   }
}

As stated in the usage, you can also apply this to the class itself to stop the debugger stepping into any code in the class. Useful if the class is full of methods etc. which you don’t need to step into.

DebuggerDisplay

Next up, is the DebuggerDisplayAttribute.

References
DebuggerDisplayAttribute Class

Usage

  • Assembly
  • Class
  • Struct
  • Enum
  • Property
  • Field
  • Delegate

Synopsis

In situations where you’re debugging and you place the mouse pointer over the an instance of MyClass (as defined previously) you’ll see the popup say something like

{MatrixTests.MyClass}

next to the variable name. This is fine if all you want is the type name or if you want to drill into the instance to view fields or properties but if you’ve got many fields or properties, it might be nicer if the important one(s) are displayed instead of the type name.

Before we delve into DebuggerDisplay, if your class implements a ToString override method then this will normally be displayed by the debugger. If you’re using this for something else, then it will not fulfill the requirements for displaying something different when the instance is hovered over. But if this ToString has everything you need then there’s no need for a DebuggerDisplay attribute.

Example

Let’s start by seeing the ToString and DebuggerDisplay that would be equivalent

public override string ToString()
{
   return $"Counter = {counter}";
}

// equivalent to 

[DebuggerDisplay("Counter = {counter}")]
public class MyClass
{
   // code
}

Both of the above will show debugger popup of “Counter = 0” (obviously 0 is replaced with the current counter value).

As you can see within the DebuggerDisplayAttribute, we can include text and properties/fields we just need to enclose them in {}. We can also use methods, within the DebuggerDisplay. Let’s assume we have a private method which creates the debugger output

[DebuggerDisplay("{DebuggerString()}")]
public class MyClass
{
   private string DebuggerString()
   {
      return $"Counter = {counter}";
   }
   // other code
}

As stated previously these all show a debugger display of “Counter = 0” – they also display quotes around the text. We can remove these by specifying nq (nq == no quotes), as per

[DebuggerDisplay("{DebuggerString(), nq}")]

So now the output display is Counter = 0 i.e. without quotes.

You can, ofcourse, extend format to display more fields/properties as per C# 6.0 string interpolation. i.e. if we have a matrix class with two properties, Rows and Columns and want to display these in the debugger display we can use

[DebuggerDisplay("Rows = {Rows}, Columns = {Columns}")]

We can also extend this syntax to use basic expressions, for example

[DebuggerDisplay("Counter = {counter + 10}")]

the above code will evaluate the counter field and then add 10 (as I’m sure you guessed).

Gotcha’s

Just remember that whatever you place in the DebuggerDisplay will be executed when you view it. So if you’re calling a remote service or database, be ready for the performance hit etc.

DebuggerNonUserCode

References

DebuggerNonUserCodeAttribute Class
Using the DebuggerNonUserCode Attribute in Visual Studio 2015
Change Debugger behavior with Attributes

Usage

  • Class
  • Struct
  • Constructor
  • Method
  • Property

Synopsis

This is very similar to DebuggerStepThrough, but as you can see from the usage, also allows us to apply this attribute to a property as a whole.

Examples

Used in the same way as DebuggerStepThrough, see those examples.

DebuggerHidden

References

DebuggerHiddenAttribute Class
Using the DebuggerNonUserCode Attribute in Visual Studio 2015
Change Debugger behavior with Attributes

Usage

  • Constructor
  • Method
  • Property

Synopsis

This is very similar to DebuggerStepThrough and DebuggerNonUserCode, but as you can see from the usage it’s somewhat restricted on what it can be applied to.

Examples

Used in the same way as DebuggerStepThrough, see those examples.

DebuggerBrowsable

References

DebuggerBrowsableAttribute Class

Usage

  • Property
  • Field

Synopsis

If you are viewing an instance of the MyClass (shown previously) within the popup debug window (displayed when you hover over the instance variable during a Visual Studio debugging session), you will see a + sign to the left of the class, meaning you can view the fields/properties in this class, but in some situations you might want to reduce the fields/properties (or what might be seen as noise). This is especially useful in situations where maybe you have lots of fields or properties which are maybe of limited usefulness in a debugging scenario, or maybe pre auto properties, you might wish to “hide” all fields. Then simply mark the field or property with

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int counter;

Now when you view the instance of MyClass, no + will appear as I’ve stipulated never display this field as browseable.

The other options for DebuggerBrowsableState are

  • DebuggerBrowsableState.Collapsed
  • DebuggerBrowsableState.RootHidden

as per Microsoft documentation…

Collapsed shows the element as collapsed whilst RootHidden does not display the root element; display the child elements if the element is a collection of array items.

Examples

// never show the field in the debugger popup
// wtahc or auto windows
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int counter;

Basically RootHidden used on an array property (for example)

public int[] Counters
{
   //
}

will not display Counters, but will displace the array of elements.

DebuggerTypeProxy

References

Using DebuggerTypeProxy Attribute

Usage

  • Assembly
  • Class
  • Struct

Synopsis

When we looked at the DebuggerDisplay we found we could reference fields/properties within the class and even use a limited set of expressions. But in some scenarios, such as the one where we added a DebuggerString to the class, it might be preferable to extract the debugger methods/properties etc. to ensure the readability and maintainability of the original class.

Examples

Let’s start by changing the MyClass code to this

[DebuggerTypeProxy(typeof(MyClassDebuggerProxy))]
public class MyClass
{
   private int counter;

   public int Counter => counter;

   public int Increment()
   {
      return counter++;
   }
}

I’ve added a property Counter, to allow us to use the counter in our proxy

Now create a simple proxy that looks like this

public class MyClassDebuggerProxy
{
}

If you now try to view the fields on an instance of MyClass the debugger will use the MyClassDebuggerProxy and in this instance there are no fields/properties and therefore nothing will be displayed (well they will if you expand Raw View but not at the top level in the debugger). So in this form, it’s a simple way to hide everything from the debugger – if that is required. Let’s be honest that’s not usually the intention, so let’s add some properties to the proxy and use the MyClass.Counter property.

public class MyClassDebuggerProxy
{
   private MyClass _instance;

   public MyClassDebuggerProxy(MyClass instance)
   {
      _instance = instance;
   }

   public int DebuggerCounter {  get { return _instance.Counter; } }
}

Now when you debug an instance of MyClass, the debugger will display the property DebuggerCounter from the proxy class. The _instance field will not be displayed. This example is a little pointless, but unlike the limited expression capability of DebuggerDisplay, the full capabilities of .NET can be used to add more data to the debugger, or change debugger displayed data.

Note: If you want to display something other than the type for the instance of MyClass, then you’ll still need to apply a DebuggerDisplay attribute to the MyClass object, not to the proxy as this will be ignored.

DebuggerStepperBoundary

References

DebuggerStepperBoundaryAttribute Class

Usage

  • Constructor
  • Method

Synopsis

This is a slightly odd concept (well it is to me at the moment). Using this attribute on a method (say our Increment method in MyClass) will in essence tell the debugger to switch from stepping mode to run mode. In other words, if you have a breakpoint on a call to myClass.Increment then press F10 or F11 (to step over or step in to the Increment method) the debugger will see the DebuggerStepperBoundary and instead do the equivalent of F5 (or run). From this perspective the use of such an attribute seems fairly limited, however the Microsoft documentation (shown in the references above) states…

“When context switches are made on a thread, the next user-supplied code module stepped into may not relate to the code that was in the process of being debugged. To avoid this debugging experience, use the DebuggerStepperBoundaryAttribute to escape from stepping through code to running code.”