【问题标题】:Is the Left-Hand Operand First broken?左手操作数是否首先被破坏?
【发布时间】:2017-09-20 18:35:36
【问题描述】:

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

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

我意识到,当 GetDataFrame 返回 null 并且 GetLearningIndex 返回零时,我会得到一个 System.DivideByZeroException 我希望根据类似System.NullReferenceException ...有什么理由吗??

【问题讨论】:

    标签: c# operators operator-precedence


    【解决方案1】:

    在进行数学运算时,首先计算左手操作数。在您的情况下,您正在调用一个返回值的方法:GetLearningIndex(),该值将始终在您使用它的任何数学运算之前进行评估。

    【讨论】:

    • 这远非全部。重要的部分是在评估 RHS 之前评估 df[0] 的哪些部分。
    【解决方案2】:

    这里有些混乱...部分赋值运算符的 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。没有检查结果是否为非 null,但评估表达式本身可能会抛出 NullReferenceException
    2. 评估indexExpression。此时未对数组执行边界检查。
    3. 评估valueExpression
    4. 将使用步骤 1 和 2 的结果表示的数组元素设置为步骤 3 的结果。是检查数组引用是否为非空且数组索引是否有效的地方执行。

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

    【讨论】:

      【解决方案3】:

      您实际上引用了错误的文档。正如the actual one 中提到的,assignement-operator is 最后被评估了。因此,您的方法调用和数学运算 (% 会在 DivideByZeroException 中的 assignemtn 产生之前进行评估。

      此外,赋值运算符是从右到左计算的,而其他所有二进制操作符都是从左到右计算的:

      除了赋值运算符,所有的二元运算符都是 左关联,意味着操作是从左到右执行的 正确的。例如,x + y + z 被计算为 (x + y) + z。这 赋值运算符和条件运算符 (?:) 是 右关联,意味着从右到右执行操作 左边。例如,x = y = z 被计算为 x = (y = z)。

      【讨论】:

        猜你喜欢
        • 2016-07-11
        • 2011-04-16
        • 2017-08-13
        • 2018-02-26
        • 2010-11-22
        • 2019-06-15
        • 2013-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多