Mark Gilbert's Blog

Science and technology, served light and fluffy.

Now you see it. Now you don’t. Subclass date constants and the VS Debugger

My colleague Doug found a good one a couple of weeks ago while trying to debug an application in Visual Studio.  At the time, I had no good explanation for what was going on.  It bugged me so (pun intended) that I tried to reproduce it, but couldn’t.  Doug and another colleague, Chris, and I took another look at it.  Not only did we manage to reproduce it, but we think we have a plausible explanation for it.

It all started with a Date constant.  A constant that seemingly wasn’t.

Doug had a Date constant defined in one of his classes.

Public Class Main
    Public Class MySubClass
        Public Const SUBCLASS_DATE As Date = #10/3/2010#
    End Class

    Private Sub NoInstantiationButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NoInstantiationButton.Click
        Me.OutputBox.AppendText(String.Format("Main SubClass Date: {0}{1}", MySubClass.SUBCLASS_DATE, vbCrLf))
    End Sub
End Class

He was stepping through code in the debugger and when he got to a statement that involved the constant, he noticed that the Date constant had a value of Nothing.  He and I looked at it and tried some things, but neither of us could make any sense of it.  He had a String constant defined in the same place, and that was showing up fine in the debugger.  Doug ultimately converted the Date constant to a Shared Readonly property that returned the date he needed.  Syntactically it looked and worked the same as the constant, so it seemed like a good workaround.

When I created a Winforms application to experiment with this, I couldn’t get it to fail.  Here was something like my first attempt:

Public Class Main
    Public Const SUBCLASS_DATE As Date = #10/3/2010#
 
    Private Sub NoInstantiationButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NoInstantiationButton.Click
        Me.OutputBox.AppendText(String.Format("Main SubClass Date: {0}{1}", SUBCLASS_DATE, vbCrLf))
    End Sub
End Class

The debugger could find the values every time.  So, I asked Doug to see his original code.  My only explanation for why Doug’s original logic was failing and mine wasn’t was that I was doing something different in my test app.  Sure enough I was: Doug’s original logic had the constant defined in a subclass, not the class where it was being used.  A little additional experimentation showed that if the Date constant was anywhere but the current class (e.g., a library class), the debugger would not show its value when you hovered over it, dropped it into the Command Window, or created a Watch from it.  Even after I set a breakpoint on the .AppendText call, and then moved past it, the SUBCLASS_DATE constant still appears to not have any value in the debugger.

At this point, we decided to look at what the class looked like in Reflector, hoping that that would shed some light on this:

 

 

 

 

Notice how the Date constants are defined – they’re fields with no value immediately assigned.  The value is defined in the .cctor, the Shared class constructor.  So, in order to have these get their value – or at least make the value available to the debugger – you have to poke it – do something that forces the constructor to be executed.  For example:

Dim X As MySubClass
X = New MySubClass
Me.OutputBox.AppendText(String.Format("Main SubClass Date (Post Instantiation): {0}{1}", MySubClass.SUBCLASS_DATE, vbCrLf))

By creating an instance of MySubClass, the constructor is forced to run, and therefore the constant receives its value.  It will now show up in all of the areas mentioned above (Command Window, Watches, etc.).  It would also work if you did something like this:

Me.OutputBox.AppendText(String.Format("Main SubClass Date: {0}{1}", MySubClass.SUBCLASS_DATE.ToString, vbCrLf))

The addition of .ToString() will flush the value out into the debugger (this particular approach seems awfully close to the solution described a previous post of mine: https://markegilbert.wordpress.com/2009/12/01/system-string-has-me-in-knots/).

There are several things I’d like to point out here:

1) None of this affects actual execution of the logic.  The date prints out just fine in the application itself.  These oddities only exist when walking through the code in the debugger.

2) None of this affects statements that depend on the actual values of the date constants.  If I were to include MySubClass.SUBCLASS_DATE (for example) in a comparison statement (with or without instantiating the containing class), the debugging would evaluate it correctly.  It simply doesn’t report the value correctly.

3) None of this affects String, Integer, Double, or Single constants (I suspect any built-in type other than Date would work).  These issues appear to strictly apply to Date constants.   Reflector shows the difference – Date constants get their values assigned in the constructor, while all others (apparently) are assigned directly in the field declaration.

 

 

4) Once the values have been flushed out with one of the above techniques, they remain available throughout the life of the debugging session.

Knowing is half the battle, but this is still confusing why this battle exists at all.  The VS debugger does recognize the Date values at some level (refer to point #2), but not all.  Very odd.

At any rate, here is the complete source for the demo built for this post.  My thanks to Doug and Chris for helping troubleshoot this.

 

Edit: The images were causing problems earlier this morning when I first posted this.  They should be correct now.

Advertisements

November 23, 2010 - Posted by | Visual Studio/.NET

Sorry, the comment form is closed at this time.

%d bloggers like this: