海森堡观察窗口
如果你正在进行类似于以下示例的按需加载等操作,那么这可能会对你造成严重影响:
private MyClass _myObj;
public MyClass MyObj {
get {
if (_myObj == null)
_myObj = CreateMyObj(); // some other code to create my object
return _myObj;
}
}
现在假设你有其他地方使用这段代码:
// blah
// blah
MyObj.DoStuff(); // Line 3
// blah
现在你想要调试你的
CreateMyObj()
方法。所以你在上面第3行设置了一个断点,打算逐步执行代码。为了保险起见,你还在上一行说
_myObj = CreateMyObj();
的地方设置了一个断点,甚至在
CreateMyObj()
内部也设置了一个断点。
代码命中了第3行的断点。你逐步执行代码。你期望进入条件代码,因为
_myObj
显然是 null,对吧?嗯...那么...为什么它跳过了条件而直接进入了
return _myObj
?! 你将鼠标悬停在 _myObj 上...确实,它有一个值!这是怎么发生的?
答案是,你的 IDE 引起了它的值变化,因为你打开了“监视”窗口,特别是“自动”监视窗口,它显示与当前或上一行执行相关的所有变量/属性的值。当你在第3行处触发断点时,监视窗口决定你会对
MyObj
的值感兴趣-因此,在不考虑任何断点的情况下,它计算了
MyObj
的值,包括设置 _myObj 值的
CreateMyObj()
调用!
这就是为什么我称之为海森堡观察窗口-你不能在不影响它的情况下观察其值... :)
注意:@ChristianHayter的评论提供了一个对这个问题的有效解决办法,所以每当你有一个惰性加载的属性时,装饰你的属性使用 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 或者 [DebuggerDisplay("<loaded on demand>")]。