为什么我应该明确地用“;未检查”;
本文关键字:检查 我应该 为什么 | 更新日期: 2023-09-27 18:11:47
有人能解释我这种奇怪的行为吗?
int i = 0x1234;
byte b1 = (byte)i;
byte b2 = (byte)0x1234; //error: const value '4660' can't convert to byte (use unchecked)
byte b3 = unchecked((byte)0x1234);
byte b4 = checked((byte)i); //throws
byte b5 = (byte)(int)0x1234; //error: same as above
注意:这是一个空的Console应用程序,启用了NO算术检查(默认为(。提前感谢大家。
编辑:我应该足够清楚,但不是所有人都清楚。
我知道一个字不能放进一个字节。但是,默认情况下,C#程序允许某些"危险"操作,主要是出于性能原因。
类似地,我可以将两个大整数相加,并且完全没有溢出。
我想知道的是上面的编译时错误:b1强制转换/赋值已编译,b2无法编译。显然没有区别,因为两者都是具有相同值的Int32。
希望现在一切都清楚了。
您被C#规范7.19节的一部分绊倒了:
除非常量表达式显式放置在
unchecked
上下文中,否则在表达式的编译时求值期间,在整型算术运算和转换中发生的溢出总是会导致编译时错误。
基本上,关键是,即使你很乐意允许操作在执行时溢出,如果你试图使用一个无法在编译时转换为目标类型的常量表达式,你也必须告诉编译器你真的知道自己在做什么。
例如,在这种情况下,你正在丢失信息——这相当于
byte b3 = 0x34;
因此,通常情况下,最好只指定它,以提供更清晰的代码,不会误导读者。想要在常量中溢出的情况相对较少——大多数情况下,您应该只指定有效值。
这不是一个奇怪的行为,字节数据类型的变量的有效范围是0-255
,但当您将HEX 0x1234
值转换为十进制时,您得到了4660
。所以unchecked用来控制溢出检查积分类型的算术运算和转换。
您可以发现unchecked
经常用于GetHashCode()
实现,该实现执行数字运算来计算最终的哈希代码。
总之,当整数类型运算的最终结果值无关紧要,但可能发生溢出时,应该使用unchecked
。
您不应该将其包围为unchecked。未选中允许将危险的值类型分配给类型,这可能会导致溢出。
byte b1 = (byte)i;
将在运行时导致溢出或强制转换异常byte b2 = (byte)0x1234;
无效,因为不能在一个字节中存储大于0xFF的值byte b3 = unchecked((byte)0x1234);
将0x34或0x12(取决于CLR实现(放入b3中,另一个字节将溢出byte b4 = checked((byte)i);
与byte b1 = (byte)i;
相同byte b5 = (byte)(int)0x1234;
将0x1234强制转换为int,然后尝试将其强制转换为byte。同样,您无法将0x1234转换为字节,因为它太大了