C# 为什么我要明确地用“我”来包围;未经检查的";?

C# 为什么我要明确地用“我”来包围;未经检查的";?,c#,casting,unchecked,C#,Casting,Unchecked,有人能解释我这种奇怪的行为吗 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 by

有人能解释我这种奇怪的行为吗

    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
注意:它是一个空的控制台应用程序,没有启用算术检查(默认情况下)。 提前谢谢大家

编辑:我应该说得很清楚,但不是全部

我知道一个字不能装入一个字节。但是,默认情况下,C#程序允许某些“危险”操作,主要是出于性能原因

类似地,我可以将两个大整数求和在一起,并且完全没有溢出

我想知道的是上面的编译时错误:b1强制转换/赋值已编译,b2无法编译。显然没有区别,因为两者都是Int32,具有相同的值


希望现在清楚了。

这不是一个奇怪的行为,数据类型变量的有效范围是
0-255
,但是当您将十六进制
0x1234
值转换为十进制时,您得到了
4660
。 所以用来控制溢出检查的整数型算术运算和转换

您可以发现,
unchecked
经常用于
GetHashCode()
实现,该实现执行数值运算来计算最终的哈希代码


总而言之,当整数类型操作的最终结果值无关紧要但可能发生溢出时,应使用
未选中的

您被C#4规范第7.19节的一部分绊倒了:

除非常量表达式显式放置在未选中的
上下文中,否则在表达式的编译时计算期间,整数类型算术运算和转换中发生的溢出总是会导致编译时错误

基本上,要点是,即使您乐于允许操作在执行时溢出,如果您试图使用在编译时无法转换为目标类型的常量表达式,您也必须告诉编译器您确实知道自己在做什么

例如,在这种情况下,您正在丢失信息-这相当于

byte b3 = 0x34;

因此,通常情况下,您最好只指定它,以提供更清晰的代码,而不会误导读者。想要在常量中溢出的情况相对较少-大多数情况下,您只需指定有效值即可。

您不应使用unchecked将其包围起来。未选中允许将危险值类型指定给可能导致溢出的类型

字节b1=(字节)i将在运行时导致溢出或强制转换异常。

字节b2=(字节)0x1234无效,因为不能在一个字节中存储大于0xFF的值。

字节b3=未选中((字节)0x1234)将0x34或0x12(取决于CLR实现)放入b3,另一个字节将溢出。

字节b4=已检查((字节)i)
字节b1=(字节)i相同


byte b5=(byte)(int)0x1234将0x1234强制转换为int,然后尝试将其强制转换为byte。同样,您不能将0x1234转换为一个字节,因为它太大。

我不会说c,我也不知道“选中”和“未选中”是什么意思,但我知道您不能在一个字节中放入四位十六进制数。您觉得哪种行为“奇怪”?你给了我们复制和实际结果的步骤,但不是预期的结果。你听起来像一位律师引用了“C 4规范第7.19节”:对我来说这没关系,但是为什么编译器不考虑“算术溢出”禁用呢?无论如何,谢谢你:这只是我偶然遇到的一个好奇心。@MarioVernari:因为这是为了改变执行时行为而设计的-大多数C#代码可能都是用这个默认值构建的,但是大多数开发人员仍然应该关心他们的常量是否溢出。@Leito:我不介意成为一名语言律师-规范是(无论如何,在某种程度上)语言的真正权威,所以在试图证明编译器行为的合理性时,提供规范参考是一种很好的做法。我同意你的看法。我只是做了一个离题的评论-所以用户原谅我-因为这样的答案并不常见,引用章节等等。这一切都归功于你。:)嗯,你说得有点对,但一点也不对。的确,避免支票是一种危险的做法,但你也应该用一点头脑来使用它们,伊姆霍。你的第一次任务导致了一个异常,这不是真的。只有启用“算术检查”(默认值为off)时,它才会抛出。我猜第三个赋值是错误的:它应该总是返回0x12。第四:与第一个相同的考虑。第五名:与第二名相同。干杯第三个将始终返回0x34,而不是0x12。如果启用了检查且值超出范围0-255,则第一个将仅导致异常。