我正在编写一段代码来阻止ushort溢出/下溢。在此之前我尝试:
ushort a = 0; //ushort.MinValue
a -= 1; //returns 65535 (ushort.MaxValue)
然后我写了真正的代码,我希望这会“失败”(无法检测到下溢):
ushort oldValue, rate, delta;
ushort newValue = Math.Max(ushort.MinValue, oldValue - rate * delta);
有趣的是,错误(CS0266)阻止我构建它。虽然我希望C#会使用ushort Max(ushort, ushort)
重载,但它会使用int Max(int, int)
重载,并且ushort
值会自动转换为int
。当然,当我明确地将结果转换为ushort
时,这很好。
这让我觉得,C#是否检测到可能发生下溢,所以它正在使用int
为我进行比较?
答案 0 :(得分:2)
这是因为oldValue - rate * delta
的结果属于int
类型。这是因为定义了运算符+, - ,*和/的“最小数据类型”是int
。因此byte
,ushort
等首先转换为int
。然后,结果再次是int
。所以你需要明确地转换为ushort
。
或者你可以使用Convert.ToUInt16
,如果发生溢出,会引发异常。
答案 1 :(得分:1)
C#将(ushort * ushort)
提升为int
,并将后续(ushort - int)
操作的结果也视为int
。最后,重载决策通过将第一个Math.Max(int, int)
参数提升为Max(ushort, int)
来为ushort
调用挑选int
。
现在你遇到的问题(除了所有未初始化的变量之外)是Max(int, int)
的结果是int
,它没有隐式转换为ushort
。
有关详细信息,请阅读规范的以下部分:
答案 2 :(得分:1)
根据this MSDN page,ushort
s的计算结果类型为int。所以你需要做的是投射计算结果
oldValue - rate * delta
回到ushort
:
(ushort)(oldValue - rate * delta)
答案 3 :(得分:1)
小于int
的较小数据类型的乘法产生int
。
因此oldValue - rate * delta
产生int
,Math.Max(short.MinValue, int)
的最佳重载是:
Math.Max Method (Int32, Int32)
(因为ushort
/ short
可以隐含地扩展到int
,无需转换)