I'm getting strange results from this method:
public static double YFromDepth(double Depth, double? StartDepth, double? PrintScale)
{
return (Depth - StartDepth ?? Globals.StartDepth) * PrintScale ?? Constants.YPixelsPerUnit ;
}
When I pass a null into St开发者_如何学GoartDepth, the coalescing is failing because "Depth - StartDepth" is being evaluated seeming by first converting StartDepth to a default of 0 (downgraded?) instead of first looking at whether it is null and substituting in the Globals.StartDepth instead.
Is this a known thing? I was able to make this work by adding parenthesis, but I really didnt expect things to work this way.
No, it's not a bug. It's the specified order of precedence - the binary -
operator has higher precedence than ??
, so your code is effectively:
return ((Depth - StartDepth) ?? Globals.StartDepth) *
PrintScale ?? Constants.YPixelsPerUnit;
If you don't want that precedence, you should specify it explicitly:
return (Depth - (StartDepth ?? Globals.StartDepth)) *
PrintScale ?? Constants.YPixelsPerUnit;
Personally I would expand the method to make it clearer:
double actualStartDepth = StartDepth ?? Globals.StartDepth;
double actualScale = PrintScale ?? Constants.YPixelsPerUnit;
return (depth - actualStartDepth) * actualScale;
As @Jon Skeet, this is an issue with precedence and can be solved by defining the correct precedence explicitly with parentheses. (e.g. (Depth - (StartDepth ?? Globals.StartDepth)) * PrintScale ?? Constants.YPixelsPerUnit;
)
This concept is not immediately obvious, and the way precedence, associativity and order of evaluation work in C# is not always intuitive.
Eric Lippert explains these concepts very well in his article Precedence vs Associativity vs Order. I highly recommend reading that article. The following are the most critical excerpts:
Precedence
Precedence rules describe how an underparenthesized expression should be parenthesized when the expression mixes different kinds of operators. For example, multiplication is of higher precedence than addition, so 2 + 3 x 4 is equivalent to 2 + (3 x 4), not (2 + 3) x 4.
Associativity
Associativity rules describe how an underparenthesized expression should be parenthesized when the expression has a bunch of the same kind of operator. For example, addition is associative from left to right, so a + b + c is equivalent to (a + b) + c, not a + (b + c). In ordinary arithmetic, these two expressions always give the same result; in computer arithmetic, they do not necessarily. (As an exercise can you find values for a, b, c such that (a + b) + c is unequal to a + (b + c) in C#?)
Order of Evaluation
Order of evaluation rules describe the order in which each operand in an expression is evaluated. The parentheses just describe how the results are grouped together; "do the parentheses first" is not a rule of C#. Rather, the rule in C# is "evaluate each subexpression strictly left to right".
It all depends on what operator precedence is set in the language. IIRC ? and ?? have pretty low precedence.
As can be seen from the order of precedence of the different operators, the null coalesce is much lower then -
or *
.
I think it is a problem with brackets....Try this:
public static double YFromDepth(double Depth, double? StartDepth, double? PrintScale)
{
return (Depth - (StartDepth ?? Globals.StartDepth)) * (PrintScale ?? Constants.YPixelsPerUnit) ;
}
HTH
精彩评论