【问题标题】:Inconsistent overflow check behavior for different types不同类型的溢出检查行为不一致
【发布时间】:2016-03-10 11:35:00
【问题描述】:

我有一段有趣的代码:

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 page on checked/unchecked context 表示以下操作会受到溢出检查的影响:

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

这里的关键字是intergal。来看看what types are considered intergal

sbyte byte char short ushort int uint long ulong

所以decimal 的行为与int 不同是有道理的,但是double 是怎么回事?

【问题讨论】:

  • 十进制与其他浮点数对象在二进制数的准确性和存储方面有所不同。详细解释here
  • unchecked 根本不影响十进制和双精度。这是标准行为。此外,这些都不依赖于动态。为了清楚起见,我建议将其删除。

标签: c# int double decimal long-integer


【解决方案1】:

首先要注意的是:

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

双倍怎么了

引用 C# 规范:

• 对于从 float 或 double 到整数类型的转换,处理取决于发生转换的溢出检查上下文(第 7.6.12 节):

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

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

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

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

所以结果是不确定的。

十进制:

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

这里可以观察到。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多