-
Notifications
You must be signed in to change notification settings - Fork 263
Visual Studio Debugger Display Attributes and Other Features
You can enhance debugging in Visual Studio by using debugger display attributes and other facilities in C#. This section shows how the DomNode
information display, described in Debugging the DOM with Visual Studio, was implemented using these features.
The string
returned from an object's ToString()
method is displayed in the object's "Value" column in Visual Studio, so you can display a different value by overriding ToString()
for the object's class.
The DomNode
class takes advantage of this to provide more information about a node:
public override string ToString()
{
if (m_type != null)
return string.Format("0x{0:x}, {1}", GetHashCode(), m_type);
return base.ToString();
}
This override method makes the Visual Studio debugger display the DomNode
's hash code and DomNodeType
:
-
GetHashCode()
returns the object's hash code, generated bySystem.GetHashCode()
. - The
m_type
field contains theDomNode
'sDomNodeType
.
You can define properties as convenient holders for all the information you want to display about a class. The DomNode
class does this with its _DebugInfo
property:
private DomNodeDebugger _DebugInfo
{
get { return new DomNodeDebugger(this); }
}
The method simply returns a newly constructed DomNodeDebugger
object. This property begins with "_" so it appears first in the list of DomNode
's properties. This property adds no additional capability to the class, nor does it change the class's operation.
The DomNodeDebugger
class is simply a package for all the information that's useful to see while debugging the DOM. It consists of a set of properties showcasing this useful data:
// The properties of this class are designed to appear in the Visual Studio debugger in
// a useful way. For example, IList<> is more useful than IEnumerable<> in the debugger view.
private class DomNodeDebugger
{
public DomNodeDebugger(DomNode node)
{
m_node = node;
}
public IList<AttributeDebugger> Attributes
{
get { return m_node.Type.Attributes.Select(attrInfo => new AttributeDebugger(attrInfo, m_node.GetAttribute(attrInfo))).ToList(); }
}
public IList<ChildDebugger> Children
{
get { return m_node.Children.Select(child => new ChildDebugger(child.ChildInfo, child)).ToList(); }
}
public IList<object> Extensions
{
get
{
var extensions = new List<object>();
for( int i = m_node.Type.FirstExtensionIndex; i < m_node.Type.FieldCount; i++)
extensions.Add(m_node.m_data[i]);
return extensions;
}
}
public IList<ListenerDebugger> AttributeChangingListeners
{
get { return m_node.GetAttributeChangingHandlers().Select(listener => new ListenerDebugger(listener)).ToList(); }
}
public IList<ListenerDebugger> AttributeChangedListeners
{
get { return m_node.GetAttributeChangedHandlers().Select(listener => new ListenerDebugger(listener)).ToList(); }
}
public IList<ListenerDebugger> ChildInsertingListeners
{
get { return m_node.GetChildInsertingHandlers().Select(listener => new ListenerDebugger(listener)).ToList(); }
}
public IList<ListenerDebugger> ChildInsertedListeners
{
get { return m_node.GetChildInsertedHandlers().Select(listener => new ListenerDebugger(listener)).ToList(); }
}
public IList<ListenerDebugger> ChildRemovingListeners
{
get { return m_node.GetChildRemovingHandlers().Select(listener => new ListenerDebugger(listener)).ToList(); }
}
public IList<ListenerDebugger> ChildRemovedListeners
{
get { return m_node.GetChildRemovedHandlers().Select(listener => new ListenerDebugger(listener)).ToList(); }
}
public override string ToString()
{
return "Additional debug info";
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly DomNode m_node;
}
DomNodeDebugger
consists of a set of properties containing DomNode
information. Note that the property getters return an IList<T>
, because that displays much more nicely in the debugger than an IEnumerable<T>
. Each property returns an IList<T>
of a another special debugging class that is a data container, such as AttributeDebugger
. These secondary classes can contain further information to display in their properties and fields. For details on how such classes are defined, see DebuggerDisplayAttribute Class.
Simply having the _DebugInfo
property that displays the contents of the DomNodeDebugger
class is a major improvement over the default view of DomNode
in the debugger. However, this display can be enhanced even further by using debugger attributes. For details, see Debugger Display Attributes.
Note that DomNodeDebugger
overrides ToString()
to create an explanatory object label, which appears as the DomNodeDebugger
object's value, as described in Overriding ToString Method.
Visual Studio has a set of attribute classes whose purpose is to format information for displaying in the debugger. For a description of these classes, see the MSDN article Enhancing Debugging with the Debugger Display Attributes.
The DomNodeDebugger
class described in Defining Properties to Display Information uses these attributes to better present information, as illustrated in Debugging the DOM with Visual Studio.
DebuggerDisplayAttribute
controls what is displayed for the attributed object. Its constructor's argument is a string that is displayed in the "Value" column for instances of the attributed type. Thus, it functions similarly to ToString()
. If you have overridden ToString()
, you do not need to use DebuggerDisplayAttribute
. If you use both, the DebuggerDisplayAttribute attribute takes precedence over ToString()
.
In addition, DebuggerDisplayAttribute
has a Name
property whose value is displayed in the debugger in the "Name" column.
For instance, DomNodeDebugger.Attributes
returns an IList<AttributeDebugger>
, and the container class AttributeDebugger
is attributed this way:
[DebuggerDisplay("{Value}", Name = "{AttributeInfo}")]
private class AttributeDebugger
{
public AttributeDebugger(AttributeInfo info, object value)
{
AttributeInfo = info;
Value = value;
}
public readonly AttributeInfo AttributeInfo;
public readonly object Value;
}
AttributeDebugger
is a container for AttributeInfo
for the DomNode
. Setting the Name
property in DebuggerDisplayAttribute
indicates that the string value of AttributeInfo
appears in the "Name" column. The value of DebuggerDisplayAttribute
's constructor's parameter appears in the "Value" column. This illustration shows the display produced by this class using this attribute:
The opened "name" node shows AttributeDebugger
's fields AttributeInfo
and Value
. Note that the contents of the "Name" and "Value" columns do indeed match AttributeInfo
and Value
.
DebuggerBrowsableAttribute
specifies how a field or property is displayed in the debugger. Its constructor takes one of the DebuggerBrowsableState
enumeration values:
-
Never
: Don't display this attributed member in the debugger. -
RootHidden
: The member is not shown, but its constituent objects are displayed if it is an array or collection. -
Collapsed
: The member is shown but not expanded in the display.
ChildDebugger
class uses this attribute to simplify the debugger display. The DomNodeDebugger
class uses ChildDebugger
to display information about each child node in its Children
property:
public IList<ChildDebugger> Children
{
get { return m_node.Children.Select(child => new ChildDebugger(child.ChildInfo, child)).ToList(); }
}
Here's how the ChildDebugger
class uses attributes:
[DebuggerDisplay("{Child}", Name = "{ChildInfo}")]
private class ChildDebugger
{
public ChildDebugger(ChildInfo info, DomNode child)
{
ChildInfo = info;
Child = child;
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public readonly ChildInfo ChildInfo; //is visible inside the child; no need to show it at top-level.
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public readonly DomNode Child; //no need to show "Child" property; go straight to DomNode members.
}
Similarly to AttributeDebugger
, ChildDebugger
uses DebuggerDisplayAttribute
to show ChildInfo
for the name and the child DomNode
for the value.
In addition, DebuggerBrowsableAttribute
marks the ChildInfo
and Child
fields to restrict their display. To see what this attribute does, here's the DomNodeDebugger.Children
node displayed with DebuggerBrowsableAttribute
marking the fields in ChildDebugger
:
Here is DomNodeDebugger.Children
displayed without DebuggerBrowsableAttribute
:
Note the differences under the opened "module" node, the first DomNode
child. Without DebuggerBrowsableAttribute
on the Child
field to hide its root, an extra Child
node appears, which is redundant because the DomNode
's information is already displayed. Without DebuggerBrowsableAttribute
on the ChildInfo
field to never display it, there's also an additional ChildInfo
node, which is also redundant, because that node is already in the child's displayed information.
Development, Debugging, and Testing
-
Debugging the DOM with Visual Studio: Shows how to get
DomNode
information to help you debugging a DOM. - Visual Studio Debugger Display Attributes and Other Features: Learn about enhancing debugging in Visual Studio by using debugger display attributes and other facilities in C#.
- Using DomExplorer: Tells about a component you can use to visualize the contents of a DOM node tree.
-
Using the DomRecorder Component: Discusses the
DomRecorder
and the DOM events it records and shows an example. - General ATF Scripting Support: Explains ATF's facilities to script applications, accessing C# objects in application classes.
-
Scripting Applications with Python: Shows how to use the
BasicPythonService
andPythonService
components to script an ATF application. - ATF Test Code: Discusses the classes to facilitate writing tests for ATF-based applications as well as ATF test code.
- Writing Python Scripts for ATF Applications: Shows how to write Python scripts for ATF applications, using existing examples.
- Home
- Getting Started
- Features & Benefits
- Requirements & Dependencies
- Gallery
- Technology & Samples
- Adoption
- News
- Release Notes
- ATF Community
- Searching Documentation
- Using Documentation
- Videos
- Tutorials
- How To
- Programmer's Guide
- Reference
- Code Samples
- Documentation Files
© 2014-2015, Sony Computer Entertainment America LLC