5

I noticed that when I view variables of certain types, such as XElement, in the Watch window in Visual Studio, if I click on the Debug Visualizers magnifying glass, the same visualizers that apply on strings (Text, XML, HTML) appear. I haven't seen this happen on any other type before. How does the debugger decide to do this?

EDIT: Here's a screenshot from the Watch window, demonstrating that XElement gets to be displayed with Text Visualizer, while System.Version (which also implements ToString) does not. enter image description here

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Omer Raviv
  • 11,409
  • 5
  • 43
  • 82

2 Answers2

5

This is actually a bit of a complex question because there are multiple pieces of the expression evaluator that control the display of custom viewers.

For the Text, XML and HTML viewer the answer is pretty easy because they are visualizers built into the debugger. If IDebugProperty2::GetPropertyInfo returns DBG_ATTRIB_VALUE_RAW_STRING as a part of the attribute flags then this visualizer will be displayed. When the user selects on of these viewers the debugger will call back into IDebugProperty3::GetStringChars / GetStrigCharLength in order to get the string value to pass to the visualizer.

For user defined visualizers though it is quite a bit more involved probably a bit to much for an answer here. MSDN does have a bit of information on how to do this though

http://msdn.microsoft.com/en-us/library/vstudio/bb162331(v=vs.100).aspx http://msdn.microsoft.com/en-us/library/vstudio/bb146621(v=vs.100).aspx

Now lets consider the specific example called out in this question: Version vs. XElement. The first thing to note is that you get different behavior depending on which language you are debugging in. C#, as you noticed, shows the visualizer only for XElement while VB.Net will show the visualizer for both XElement and Version. This is unsurprising in some ways because the visualizer flag is controlled by the EE and each language has their own implementation

C# algorithm

If the value is typed to String or has an implicit reference conversion to XNode then the visualizer is displayed.

In this case XElement derives from XNode hence it gets the visualizer. The Version type does not derive from XNode and it's not String so it does not get the visualizer

VB.Net algorithm

If the value being displayed meets one of the following then the visualizer is displayed

  1. String or has a ToString override
  2. Has a DebuggerDisplay which points to a value that qualifies for 1 or 2

In this case both XElement and Version override ToString hence the visualizer is shown in both cases

Why the difference?

Beats me. When I wrote the VB.Net implementation I wanted to support the visualizer in as many places as possible (it's really useful). Hence whenever the final value being displayed was a String I displayed the visualizer. I didn't really think to consult the C# team when I made this decision. Until I researched the code base to answer this question I wasn't even aware there was a difference :)

Omer Raviv
  • 11,409
  • 5
  • 43
  • 82
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Right, I did notice that GetPropertyInfo does indeed return DBG_ATTRIB_VALUE_RAW_STRING on XElement values, but that doesn't happen in, for instance, System.Xml.XmlDocument values. Why is that? – Omer Raviv Feb 27 '14 at 19:49
  • @OmerRaviv `XElement` overrides the `ToString` method and the EE uses the `string` value as the display and accordingly sets tho `DBG_ATTRIB_VALUE_RAW_STRING` flag. `XmlDocument` does not hence it doesn't get the attribute. If you manually call `ToString` it will show up though – JaredPar Feb 27 '14 at 20:21
  • Sorry, bad example. Take `System.Version` instead - it overrides `ToString()`, but doesn't have the Text Visualizers show up in the Watch window, nor does it have the `DBG_ATTRIB_VALUE_RAW_STRING` attribute. Also, usually, when the C# EE is showing a value's ToString(), it surrounds it with curly braces. That's not the case for `XElement`. I'm curious as to what makes XElement so special? – Omer Raviv Feb 27 '14 at 21:26
  • @OmerRaviv what version of Visual Studio and .Net are you debugging here? I think the definition of `XElement` changed to cause this diff – JaredPar Feb 27 '14 at 21:33
  • .Net 4.5.1 VS2013 Update2 CTP, but I've reproduced it with .Net4 in VS2010 as well. – Omer Raviv Feb 27 '14 at 21:38
  • @OmerRaviv I understand this now, will update my answer shortly – JaredPar Feb 28 '14 at 01:57
0

How does the debugger decide to do this?

It has a registry of visualizers depending on the object type.

You are free to write your own.

If you do not see a visualizer, then simply none has been registered. And VS comes with some good standard ones.

TomTom
  • 61,059
  • 10
  • 88
  • 148