1

我实际上在未经检查的上下文中测试了 C# 中的强制转换行为。就像文档说的那样,在未经检查的情况下,演员阵容总是成功的。但有时,在特定情况下,从一种特定类型转换为另一种类型会产生意想不到的结果。

例如,我测试了三个“double to sbyte”转换:

var firstCast = (sbyte) -129.83297462979882752;          // Result : 127.
var secondCast = (sbyte) -65324678217.74282742874973267; // Result : 0.
var thirdCast = (sbyte) -65324678216.74282742874973267;  // Result : 0.

为了清楚起见,第二个和第三个 double 之间的区别只是1( secondDouble - firstDouble = 1)。在这种情况下,强制转换的结果似乎总是0针对任何“大”双值。

我的问题是:为什么第二次和第三次强制转换会导致0?我在 C# 文档中搜索了答案,但没有找到任何答案。

我使用 .Net Framework 4.7.2 测试了上述内容。

4

1 回答 1

3

根据C# 语言规范

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

如果不使用checkedorunchecked运算符,默认情况下溢出检查上下文是未选中的,所以我们看一下:

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

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

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

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

在这里,这些值既不是 NaN 也不是无限的。当向零舍入时,它们不在有效范围内sbyte,即 -128 到 127,因此适用最后一个要点,这意味着这种强制转换的结果是未指定的。

换句话说,此转换的结果取决于您使用的编译器。不同的编译器可以做不同的事情,它们仍然被称为 C# 编译器。您使用的任何编译器都可能认为,当要转换的值非常远离下限/上限时,为转换返回 0 会是一个更好的主意。

于 2020-01-15T16:45:36.983 回答