The Heisenberg Watch Window
This can bite you badly if you're doing load-on-demand stuff, like this:
private MyClass _myObj;
public MyClass MyObj {
get {
if (_myObj == null)
_myObj = CreateMyObj(); // some other code to create my object
return _myObj;
}
}
Now let's say you have some code elsewhere using this:
// blah
// blah
MyObj.DoStuff(); // Line 3
// blah
Now you want to debug your CreateMyObj()
method. So you put a breakpoint on Line 3 above, with intention to step into the code. Just for good measure, you also put a breakpoint on the line above that says _myObj = CreateMyObj();
, and even a breakpoint inside CreateMyObj()
itself.
The code hits your breakpoint on Line 3. You step into the code. You expect to enter the conditional code, because _myObj
is obviously null, right? Uh... so... why did it skip the condition and go straight to return _myObj
?! You hover your mouse over _myObj... and indeed, it does have a value! How did THAT happen?!
The answer is that your IDE caused it to get a value, because you have a "watch" window open - especially the "Autos" watch window, which displays the values of all variables/properties relevant to the current or previous line of execution. When you hit your breakpoint on Line 3, the watch window decided that you would be interested to know the value of MyObj
- so behind the scenes, ignoring any of your breakpoints, it went and calculated the value of MyObj
for you - including the call to CreateMyObj()
that sets the value of _myObj!
That's why I call this the Heisenberg Watch Window - you cannot observe the value without affecting it... :)
GOTCHA!
Edit - I feel @ChristianHayter's comment deserves inclusion in the main answer, because it looks like an effective workaround for this issue. So anytime you have a lazy-loaded property...
Decorate your property with [DebuggerBrowsable(DebuggerBrowsableState.Never)] or [DebuggerDisplay("<loaded on demand>")]. – Christian Hayter
System.Drawing
(Point, Size, Rectangle, and float versions) are all mutable.Color
isn't, though. – Carrackdt.NextDays(1);
, programmers won't have a notion that it changes its own value. In the same vein that data structure constructs (e.g.node->next
,node.next
) doesn't modify the value of node. And.. it's too late now, they could givedt.AddDays(1)
the semantics that it add days in its own value. – Clannishdt.PlusDays(1)
would be clearer. Another issue with that method is it only accepts adouble
value, so the result isn't exact. – Kill