左手操作数是否首先被破坏?

Is the Left-Hand Operand First broken?

根据Precedence and order of evaluation left 将在 right 之前被评估。但是,我有一个项目:

int[] df = null;  //GetDataFrame()
int xIndex =  12; //GetLearningIndex()
df[0] = 1 % GetLearningIndex();

我意识到,当 GetDataFrame returns nullGetLearningIndex returns 零 我得到一个 System.DivideByZeroException 我会根据 System.NullReferenceException 之类的期望......有什么原因吗??

当涉及到数学运算时,左手操作数首先被评估。在你的例子中,你正在调用一个方法,其中 returns 一个值:GetLearningIndex(),在你使用它的任何数学运算之前总是会计算这个值。

您实际上指的是错误的文档。正如在 the actual one 中提到的,赋值运算符 最后评估的。因此,您的方法调用以及数学运算(%DivideByZeroException.

中的赋值结果之前被评估

此外,赋值运算符是从右到左求值的,这与其他所有从左到右求值的二元运算符形成对比:

Except for the assignment operators, all binary operators are left-associative, meaning that operations are performed from left to right. For example, x + y + z is evaluated as (x + y) + z. The assignment operators and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. For example, x = y = z is evaluated as x = (y = z).

这里有些混乱...首先评估赋值运算符的 LHS 的 部分 。特别地,表达式 df0 将在 之前被评估 GetLearningIndex,但数组元素赋值(包括索引验证)仅发生 之后结果已经计算出来了。

下面是显示更多详细信息的示例:

using System;

public class Test
{
    private int[] array = new int[10];

    static void Main()
    {
        Test instance = null;

        // This would throw a NullReferenceException
        // because instance is null at the start of the statement.
        // ExecuteSideEffect never gets called.        
        // instance.array[100] = ExecuteSideEffect(() => instance = new Test());

        instance = new Test();

        // This would throw an IndexOutOfBoundsException
        // because instance.array is evaluated before ExecuteSideEffect.
        // The exception is only thrown when the assignment is performed.
        // instance.array[100] = ExecuteSideEffect(() => instance.array = new int[1000]);

        int index = 5;
        // This modifies array index 5 because index is evaluated
        // before EvaluateSideEffect
        instance.array[index] = ExecuteSideEffect(() => index = 1);
        Console.WriteLine(instance.array[5]); // 10
    }

    private static int ExecuteSideEffect(Action action)
    {
        action();
        return 10;
    }
}

所以在这种形式的声明中:

arrayExpression[indexExpression] = valueExpression;

执行顺序为:

  1. 评价arrayExpression。没有检查结果是否为非空,但评估表达式本身可能会抛出 NullReferenceException.
  2. 评价indexExpression。此时不对数组执行边界检查。
  3. 评价valueExpression
  4. 将使用步骤 1 和 2 的结果表示的数组元素设置为步骤 3 的结果。这里 是检查数组引用是否为非空以及执行数组索引有效。

据我所知,目前这方面的规定很糟糕 - 我会提出一个问题,看看我们是否可以在 ECMA C# 5 标准中修复它。