不同类型的溢出检查行为不一致

本文关键字:不一致 溢出检查 同类型 | 更新日期: 2023-09-27 18:25:50

我有一段有趣的代码:

private static int ConvertToInt(dynamic value)
{
    unchecked
    {
        return (int)value;
    }
}
Console.WriteLine(ConvertToInt(long.MaxValue));
Console.WriteLine(ConvertToInt(double.MaxValue));
Console.WriteLine(ConvertToInt(decimal.MaxValue));

该输出:

-1
-2147483648
System.OverflowException: Value was either too large or too small for an Int32.

我觉得这有点奇怪。为什么即使我明确指定了unchecked,从decimal转换为int也会引发OverflowException

编辑:很有趣。已检查/未检查上下文上的MSDN页面表示以下操作受到溢出检查的影响:

积分类型之间的显式数字转换。

这里的关键字是intergal。让我们看看哪些类型被认为是星系间的:

sbyte字节字符短ushort int uint长ulong

因此,decimal的行为与int不同是有道理的,但double怎么了?

不同类型的溢出检查行为不一致

首先要注意的是:

  1. unchecked完全不影响小数和双精度
  2. 这些都不依赖于动态

双怎么了

引用C#规范:

•对于从浮点型或双精度型到整型的转换,处理取决于进行转换的溢出检查上下文(§7.6.12):

o在未检查的上下文中,转换总是成功的,并按如下方式进行。

•如果操作数的值是NaN或无穷大,则转换的结果是目标类型的未指定值。

•否则,源操作数将向零四舍五入到最接近的整数值。如果这个整数值在目标类型的范围内,那么这个值就是转换的结果。

否则,转换的结果是目标类型的未指定值

因此,结果是未知的。

十进制大小写:

•对于从十进制到整型的转换,源值将向零四舍五入到最接近的整数值,该整数值将成为转换的结果。如果生成的整数值在目标类型的范围之外,则会引发System.OverflowException。

这是在这里观察到的。

这个问题很有趣,也很有效,但如果你非要问它,那就是代码气味的问题。除非在特殊情况下,否则不要依赖奇怪的转换。问题中提到的所有三种转换都不应该发生在真实世界的代码中,此外,我建议编译checked,除非有理由不这样做。通常,大多数时间不是花在应用程序代码上,而是花在其他代码上(例如库或对后端系统的调用)。checked的性能损失在这些情况下并不明显。