VS2015断点调试神坑之为引用变量赋值为null不成功?

来源:互联网 发布:最好背单词软件 编辑:程序博客网 时间:2024/06/04 19:00

先来看一个gif:



什么情况?明明已经赋值把obj.m_pA赋值为null了,可是为什么单步调试后m_pA却依然有值,而且m_pA.nVal的值还从0变成了1?为了搞明白这个问题,我们先来看下DebugTest的结构:

class DebugTest    {        static int nCount = 0;        public DebugTest()        {            m_pA = new A();        }        public class A        {            public A()            {                nVal = DebugTest.nCount++;            }            int nVal;        }        public A m_pA;        A AVal        {            get            {                if (null == m_pA)                {                    m_pA = new A();                }                return m_pA;            }        }    }


可以看到,DebugTest中有一个类型为A的Public变量,有一个返回A的AVal属性,并且AVal这个属性并不是单纯的返回m_pA,他有多做一个m_pA为null的话,就创建一个A实例的判断。每创建一个A类对象,对象实例中的nVal值就加1。


聪明如你,可能看到这就领悟到了,难道是在把m_pA赋为null后,又自动创建了一个A对象?没错!但问题是在哪里,什么时候创建的呢?我们再看一张图就明白了:

原因就是:在执行obj.m_pA = null;这行代码前,变量查看窗口已经对obj实例进行了展开,执行完这行代码后会刷新变量查看窗口中的obj变量,由于它是展开的,所以为了知道AVal的值,VS内部就执行了一遍AVal,然后根据AVal的逻辑,m_pA为空,于是创建了一个新的A类实例赋值给m_pA变量,在新的实例构造的时候,把最新的DebugTest.nCount 值1赋给了A.nVal。这也就解释了我们一开始看到的gif图中奇怪的现象。


其实到这边都还算好理解,坑的是,在新的A类对象构造的时候,既在A的构造函数段不到点(可能是出于如果段到了点,堆栈怎么显示的问题?),也没有任何的提示。所以如果你不知道这个坑又刚好不幸中招的话,那么你在断掉调试的时候可能就会发生很多完全理解的问题,这得取决于你在查看变量的展开类的属性中做了什么事。有可能是引用赋值为null后又有值了,有可能是某个变量突然莫名其妙的变化了等等。

如果以后发生了直接运行没什么问题,但是断掉调试的时候莫名其妙的情况,可以往这个方向上先考虑一下,排除是因为查看变量展开导致调用了属性的问题。

阅读全文
0 0
原创粉丝点击