Mat*_*ine 5 c# evaluation nullreferenceexception
为什么下面NullReferenceException
的声明崩溃a.b.c = LazyInitBAndReturnValue(a);
?
class A {
public B b;
}
class B {
public int c;
public int other, various, fields;
}
class Program {
private static int LazyInitBAndReturnValue(A a)
{
if (a.b == null)
a.b = new B();
return 42;
}
static void Main(string[] args)
{
A a = new A();
a.b.c = LazyInitBAndReturnValue(a);
a.b.other = LazyInitBAndReturnValue(a);
a.b.various = LazyInitBAndReturnValue(a);
a.b.fields = LazyInitBAndReturnValue(a);
}
}
Run Code Online (Sandbox Code Playgroud)
赋值表达式从右到左进行计算,因此在我们分配时a.b.c
,a.b
不应为null.奇怪的是,当调试器中断异常时,它也显示a.b
为初始化为非空值.
C# 规范第 7.13.1 节对此进行了详细介绍。
x = y 形式的简单赋值的运行时处理包括以下步骤:
- 如果 x 被分类为变量:
- x 被评估以产生变量。
- y 被计算,如果需要,通过隐式转换转换为 x 的类型(第 6.1 节)。
- 如果 x 给出的变量是引用类型的数组元素,则执行运行时检查以确保为 y 计算的值与 x 为元素的数组实例兼容。如果 y 为 null,或者存在从 y 引用的实例的实际类型到包含 x 的数组实例的实际元素类型的隐式引用转换(第 6.1.4 节),则检查成功。否则,将引发 System.ArrayTypeMismatchException。
- 对 y 求值和转换得到的值存储到 x 求值给出的位置。
- 如果 x 被分类为属性或索引器访问:
- 计算与 x 关联的实例表达式(如果 x 不是静态)和参数列表(如果 x 是索引器访问),并将结果用于后续的 set 访问器调用。
- y 被计算,如果需要,通过隐式转换转换为 x 的类型(第 6.1 节)。
- 使用为 y 计算的值作为其值参数来调用 x 的 set 访问器。
我认为底部部分(如果 x 被分类为属性或索引器访问)提供了提示,但也许 C# 专家可以澄清。
首先生成一个set 访问器y
,然后对其求值(触发断点),然后调用该set 访问器,这会导致空引用异常。如果我必须猜测,我会说访问器指向 的旧值b
,该值为空。当您更新 时b
,它不会更新它已经创建的访问器。
归档时间: |
|
查看次数: |
82 次 |
最近记录: |