C# Math.Max 类型处理
本文关键字:处理 类型 Max Math | 更新日期: 2023-09-27 18:36:26
我正在编写一段代码来防止 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
为我进行比较?
这是因为oldValue - rate * delta
的结果是int
类型。这是因为定义运算符 +、-、* 和/的"最小数据类型"是int
。所以byte
、ushort
等首先转换为int
。然后,结果又是一个int
.所以你需要显式投射到ushort
.
或者,您可以使用Convert.ToUInt16
,如果发生溢出,它将引发异常。
根据此 MSDN 页,使用 ushort
s 的计算的结果类型为 int。所以你需要做的是投射计算的结果
oldValue - rate * delta
返回ushort
:
(ushort)(oldValue - rate * delta)
C# 将(ushort * ushort)
提升为int
,并将后续(ushort - int)
操作的结果也作为int
。最后,重载解析通过将第一个ushort
参数提升到 int
来为Max(ushort, int)
调用选取Math.Max(int, int)
。
现在你遇到的问题(除了所有未初始化的变量之外)是Max(int, int)
的结果是一个int
,它没有隐式转换为ushort
。
有关详细信息,您可以阅读规范的以下部分:
- 7.3.6.2 二进制数字提升("否则,两个操作数都转换为 int 类型。
- 6.1.2 隐式数值转换
- 7.5.3 重载解析
int
数据类型的乘法会产生int
结果。
因此oldValue - rate * delta
会导致int
,Math.Max(short.MinValue, int)
的最佳过载是:
Math.Max Method (Int32, Int32)
(因为ushort
/short
可以隐式扩大到int
,无需转换)