C#中的int和byte转换

33

为什么

byte someVar;
someVar -= 3; 

合法但

byte someVar;
someVar = someVar - 3;

不是吗?

2个回答

35

令人惊讶的是,当你对字节进行操作时,计算将使用int值完成,首先会将字节隐式地转换为(int)。这也适用于short,类似地,在进行浮点运算时,float被上升转换为double

第二个代码片段等同于:

byte someVar;
someVar = (int) someVar - 3;

因此,你必须将结果强制转换回 (byte),以使编译器接受赋值。

someVar = (byte) (someVar - 3);

有人能验证一下在 someVar-=3; 的例子中,类型转换是否发生在 IL 级别?它是否生成相同的 IL 代码? - Dested
2
我刚刚使用 Reflector 进行了检查。-= 运算符在 IL 级别生成 conv.u1,这就是为什么第一个代码片段可以正常工作的原因。 - Thomas Levesque
5
具体规则可以在C#语言规范中找到。其中规定:“上述第二条规则允许在特定情况下将x op= y作为 x = (T)(x op y)进行计算。这个规则是为了让预定义的运算符可用作复合运算符,当左操作数的类型为sbytebyteshortushortchar时。即使两个参数都属于这些类型,预定义的运算符也会生成一个int类型的结果,如§7.3.6.2中所述。因此,如果没有强制转换,将无法将结果赋值给左操作数。” - Jeppe Stig Nielsen

11
这里有一个来自CLI规范(Ecma 335)的表格副本,它指定了二元数值运算符类型A op B中哪些操作数是有效的,其中A和B是操作数,“op”是运算符,例如您在片段中使用的Opcodes.Sub: alt text 需要对此进行一些注释:
- “native int”在C#程序中表示IntPtr - “F”代表浮点类型,在C#中是double或float - “&”表示指针值,方框是阴影的,因为它们是不安全的操作 - “O”表示对象引用 - “x”是不允许的操作。
请注意,F所在的行和列,两个操作数都必须是浮点数,您不能直接将int加到double中。 C#编译器通过自动将int操作数转换为double,使运算符有效来处理该限制。
与您的问题相关的是,请注意byte,sbyte,char,short和ushort类型不存在。同样的方法,编译器将操作数转换为可以表示该值的最小类型,以便可以使用运算符。这将是int32。根据表格,操作的结果将是int32。
现在有个问题:结果是int32,但将其分配回byte值需要缩小转换。从32位到8位。那是麻烦的,因为它会丢失重要的位。 C#编译器要求您明确表示这一点。您基本上承认自己知道自己在做什么,并且意识到可能产生令人惊讶的结果,像这样:
byte v = 255;
v = (byte)(v + 1);

-=运算符存在问题,因为没有有效的方式应用所需的强制转换。它无法在语言语法中表示。使用(byte)3没有意义,文字本身也会被转换为int32以使运算符正常工作。

他们避免了这个问题,编译器会自动发出转换而不需要你的帮助。


这就解释了为什么我无法使用反射在类型之间进行隐式转换。 - fusi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接