数値に対する拡張メソッドを書いていて、リテラルに対して実行したときにハマったのでメモ。
例えば、以下のような拡張メソッドがあったとして、
public static class NumEx
{
public static double Ceiling(this double num) => Math.Ceiling(num);
}
次のように負数の数値リテラルに対して実行すると期待した値とは異なる値が返ってくる。
Console.log(-1.5.Ceiling()); // --> -1.0を期待
> -2 // しかし実行すると-2.0が返る
これは演算子の優先順位の問題で、マイナスの単項演算子の優先順位が拡張メソッドの
呼び出しよりも弱いために、拡張メソッドの呼び出し結果に対してマイナスの単項演算子
が評価されているためこうなってしまう。
Console.log(-1.5.Ceiling()); // <- この記述は
Console.log(-(1.5.Ceiling())); // <- このように解釈される
回避するには、リテラルに対して直接拡張メソッドを実行するのではなく、いったん変数に
格納してやるか、()で括って優先順位を明示的に示してやればよい。
var n = -1.5;
Console.log(n.Ceiling());
> -1
Console.log((-1.5).Ceiling());
> -1
リテラルに対して拡張メソッドを実行するときは意識しておかないと、忘れたころにまたハマりそう。