空合并操作顺序

本文关键字:顺序 操作 合并 | 更新日期: 2023-09-27 17:58:30

我从这个方法得到了奇怪的结果:

public static double YFromDepth(double Depth, double? StartDepth, double? PrintScale)
{               
    return (Depth - StartDepth ?? Globals.StartDepth) * PrintScale ?? Constants.YPixelsPerUnit ;
}

当我将null传递到StartDepth中时,合并失败了,因为"Depth-StartDepth"的计算方法似乎是先将StartDepth转换为默认值0(降级?),而不是先查看它是否为null并替换为Globals.StartDepth。

这是已知的事情吗?我可以通过添加括号来实现这一点,但我真的没想到事情会这样。

空合并操作顺序

不,这不是一个bug。这是指定的优先级顺序-二进制-运算符的优先级高于??,因此您的代码实际上是:
return ((Depth - StartDepth) ?? Globals.StartDepth) * 
          PrintScale ?? Constants.YPixelsPerUnit;

如果你不想要这个优先级,你应该明确地指定它:

return (Depth - (StartDepth ?? Globals.StartDepth)) * 
          PrintScale ?? Constants.YPixelsPerUnit;

就我个人而言,我会扩展方法以使其更清晰:

double actualStartDepth = StartDepth ?? Globals.StartDepth;
double actualScale = PrintScale ?? Constants.YPixelsPerUnit;
return (depth - actualStartDepth) * actualScale;

作为@Jon Skeet,这是一个优先级问题,可以通过用括号明确定义正确的优先级来解决。(例如(Depth - (StartDepth ?? Globals.StartDepth)) * PrintScale ?? Constants.YPixelsPerUnit;

这个概念并不明显,C#中优先级关联性评估顺序的工作方式并不总是直观的。

Eric Lippert在他的文章《先例与关联性与秩序》中很好地解释了这些概念。我强烈建议你读那篇文章。以下是最关键的摘录:

优先级

优先级规则描述了当表达式混合了不同类型的运算符时,应如何将括号不足的表达式加括号。例如,乘法的优先级高于加法,因此2+3 x 4等效于2+(3 x 4),而不是(2+3)x 4。

关联性

关联性规则描述了当表达式具有一组相同类型的运算符时,应如何将带括号不足的表达式加括号。例如,加法从左到右是关联的,因此a+b+c等价于(a+b)+c,而不是a+(b+c)。在普通算术中,这两个表达式总是给出相同的结果;在计算机算术中,它们不一定。(作为练习,你能找到a、b、c的值吗?这样(a+b)+c就等于c#中的a+(b+c)?)

评估顺序

求值顺序规则描述了表达式中每个操作数的求值顺序。括号只是描述了结果是如何组合在一起的;"先做括号"不是C#的规则。相反,C#中的规则是"严格从左到右计算每个子表达式"。

这完全取决于语言中设置的运算符优先级。IIRC?和具有相当低的优先级。

从不同运算符的优先级顺序可以看出,null合并比-*低得多。

我认为括号有问题。。。。试试这个:

public static double YFromDepth(double Depth, double? StartDepth, double? PrintScale)
{               
    return (Depth - (StartDepth ?? Globals.StartDepth)) * (PrintScale ?? Constants.YPixelsPerUnit) ;
}

HTH