In
SharpDevelop 4.1 the debugger has a completely new functionality called
Debugger visualizers. This post presents two new visualizers which are included
in the standard release of SharpDevelop and shows how to implement your own
visualizers.
Object graph visualizer
The Object
graph visualizer is designed for debugging data structures. It presents live data
structures in a program in the same way people draw data structures on a whiteboard
- boxes represent instances and arrows represent references between them:

To help debug
algorithms operating on the structures, animated transitions are shown when a
step is performed in the debugger. This is best explained by a video.
Collection visualizer
The second
visualizer is designed for easier debugging of collections. Before introducing the
visualizer, let's look at a familiar view of how collections are commonly being presented:

The problem
is that the tooltip does not show any useful information. To actually see anything
we have to expand and collapse individual items, one by one. Could we do
better? Enter the Collection visualizer:


This view
shows all the properties at once. You can select interesting properties using
the ComboBox in the top right corner (selecting fewer properties makes
scrolling faster).
Adding your own
visualizers
The
visualizers are extensible in the sense that you can implement your own
visualizers and make them appear in the standard visualizer selector in SharpDevelop.
Say we want to implement a visualizer that shows syntax highlighted XML
strings:

This is
actually quite simple. We need to specify three things:
- For
which types will the visualizer be available
- What
should happen when user executes the visualizer
- The
label in the UI („Xml visualizer")
First we
implement IVisualizerDescriptor:
public class XmlVisualizerDescriptor : IVisualizerDescriptor
{
public bool IsVisualizerAvailable(DebugType type)
{
return type.FullName == typeof(string).FullName;
}
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
{
return new XmlVisualizerCommand(expression);
}
}
Then we
implement a command that defines the behavior:
public class XmlVisualizerCommand : ExpressionVisualizerCommand
{
public XmlVisualizerCommand(Expression expression) :base(expression) { }
public override string ToString()
{
return "Xml visualizer"; // label in the UI
}
public override void Execute()
{
// Our visualizer was selected.
// We can do anything here - in this case we open a window showing the value of the variable.
string expressionValue = this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString();
var window = new XmlVisualizerWindow(expressionValue);
window.ShowDialog();
}
}
The XmlVisualizerWindow
is just a simple WPF Window with a multiline TextBox showing the string,
highlighted using the built-in syntax highlighting of AvalonEdit. The only remaining thing to do
is to tell SharpDevelop about our new visualizer. This is done by adding the
following into our .addin file:
<Path name="/SharpDevelop/Services/DebuggerService/Visualizers">
<Class class="YourNamespace.XmlVisualizerDescriptor" />
</Path>
Now SharpDevelop
will offer our new visualizer for String variables and execute our code when
the visualizer is selected:

Note
The XML
Visualizer shown here is also a part of the standard release of SharpDevelop.
Note that
this functionality is not analogous to Visual Studio's debugger visualizers
which work by passing serialized objects from the program to the debugger and
therefore:
-
require
types to be Serializable
- cannot
perform lazy loading as the whole object has to be serialized and passed at
once
- require types
to be annotated with attributes
The
visualizers in SharpDevelop are currently implemented as SharpDevelop AddIns and use the debugger API, which allows for more
flexibility than when passing a serialized object. This was needed to efficiently
implement the Collection and Object graph visualizers. Adding also a serialization based API for simpler visualizers is a good idea for the future.
Notes on implementation
Implementing
the Collection and Object graph visualizers was quite interesting. To achieve
reasonable performance, the Collection visualizer queries only the values that
are actually visible (getting values from the debugger is quite expensive as it
involves interprocess communication).
In the
Object Graph visualizer it was not easy to detect shared references because the
garbage collector is moving objects around in memory while the debugger is
trying to determine how the graph actually looks (see David's post on debugger internals). Another
challenge was how to layout the graph and draw the edges dynamically so that the
nodes of the graph do not move around too wildly on every small change to the
graph.
In case you
are interested to read more, I recently wrote a Master thesis about this which covers everything
in depth.
Conclusion
Hope you
will find these features useful. In case of any issues or ideas for improvement
feel free to comment on this post or drop me an email (martin.konicek at gmail.com).