c# - 成员引用和评估的分配顺序

标签 c# nullreferenceexception evaluation

为什么以下语句会因 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);
    }
}

赋值表达式被求值from right to left ,因此当我们分配给 a.b.c 时,a.b 不应为空。奇怪的是,当调试器因异常而中断时,它也将 a.b 显示为已初始化为非空值。

Debugger on break

最佳答案

这在 Section 7.13.1 中有详细说明C# 规范。

The run-time processing of a simple assignment of the form x = y consists of the following steps:

  • If x is classified as a variable:
    • x is evaluated to produce the variable.
    • y is evaluated and, if required, converted to the type of x through an implicit conversion (Section 6.1).
    • If the variable given by x is an array element of a reference-type, a run-time check is performed to ensure that the value computed for y is compatible with the array instance of which x is an element. The check succeeds if y is null, or if an implicit reference conversion (Section 6.1.4) exists from the actual type of the instance referenced by y to the actual element type of the array instance containing x. Otherwise, a System.ArrayTypeMismatchException is thrown.
    • The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
  • If x is classified as a property or indexer access:
    • The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent set accessor invocation.
    • y is evaluated and, if required, converted to the type of x through an implicit conversion (Section 6.1).
    • The set accessor of x is invoked with the value computed for y as its value argument.

我认为底部部分(如果 x 被分类为属性或索引器访问)提供了一个提示,但也许 C# 专家可以澄清。

首先生成一个set accessor,然后评估y(触发你的断点),然后调用set accessor,这导致空引用异常。如果非要我猜的话,我会说 accessor 指向 b 的旧值,它是 null。当您更新 b 时,它不会更新它已经创建的访问器。

关于c# - 成员引用和评估的分配顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24048389/

相关文章:

c# - 如何将接口(interface)对象传递给 WebMethod?

c# - .NET 服务器垃圾回收和对象生命周期

asp.net - Linq,如何检查字段的值是否为空

javascript - 错误无法获取未定义或空引用的属性 'options'

ASP.NET 应用程序从 Session.Remove 实现中引发 System.NullReferenceException

variables - 在Kotlin中,是否可以使用变量来调用方法或属性?

c# - .net 代码隐藏页面中的 GetElementsByTagName 功能?

c# - 数组内存分配说明

PHP 手册 : Number Conversion in Is_Numeric Example 1?

evaluation - 评估开发人员