调试if块时触发Object reference not set to an instance of an object异常
调试中遇到的空引用异常诡异场景
现象描述
代码片段1
if (result.success) { List<int> productids = addOrder.items.Select(x=>x.product_id).ToList(); //More code }
调试器进入if块执行时,抛出Object reference not set to an instance of an object异常。
代码片段2
添加无关初始化代码后:
if (result.success) { var a = 10; var b = a + 10; var c = a + b; var foo = new orders(); List<int> productids = addOrder.items.Select(x=>x.product_id).ToList(); //More code }
a、b、c、foo初始化均正常,但执行productids初始化时仍抛出异常,且确认addOrder.items和x.product_id均不为null(请求传入并正确反序列化)。
代码片段3
将if条件改为true后:
if (true) { var a = 10; var b = a + 10; var c = a + b; var foo = new orders(); List<int> productids = addOrder.items.Select(x=>x.product_id).ToList(); //More code }
代码可正常执行。
完整函数代码
Foo result = null; try{ //More code result = await GetResult(); //More code if(result.success){ List<int> productids = addOrder.items.Select(x=>x.product_id).ToList(); //More code } } catch(Exception ex){ /* Some Code . . . */ }
核心困惑
调试时执行不依赖未初始化变量的代码却触发空引用异常,需明确问题原因。
问题原因分析
这种诡异现象主要由以下几种情况导致:
- JIT编译器的条件分支优化:
当使用if(result.success)作为分支条件时,JIT会对代码执行顺序进行重排,提前加载result的相关成员。即便调试器显示进入了if块,result内部可能仍有未完全初始化的部分,或者success属性的getter方法内部存在未处理的空引用操作(比如依赖其他未初始化的成员),间接引发后续代码异常。 - 异步方法的半初始化对象:
await GetResult()返回的result可能未完成完全初始化就被后续代码访问。如果GetResult()内部存在非线程安全的对象构造逻辑,异步场景下容易导致result处于半就绪状态,此时访问result.success会埋下异常隐患。 - 调试器的执行时机偏差:
调试器的“进入if块”提示可能存在视觉偏差,实际代码执行时,result的状态还未满足安全访问条件,后续执行addOrder.items.Select时,受之前result访问的影响触发异常。
当改为if(true)后,JIT将分支内代码标记为必然执行路径,跳过条件分支相关的优化逻辑,同时避免了对result的提前访问,因此代码能正常运行。
内容的提问来源于stack exchange,提问作者Muhammad Jamali
相关产品推荐
相关产品推荐

