【发布时间】:2011-04-08 03:55:05
【问题描述】:
为什么
byte someVar;
someVar -= 3;
有效但
byte someVar;
someVar = someVar - 3;
不是吗?
【问题讨论】:
为什么
byte someVar;
someVar -= 3;
有效但
byte someVar;
someVar = someVar - 3;
不是吗?
【问题讨论】:
令人惊讶的是,当您对字节执行操作时,将使用int 值完成计算,首先将字节隐式转换为(int)。 shorts 也是如此,类似地,floats 在进行浮点运算时会向上转换为 double。
第二个sn-p相当于:
byte someVar;
someVar = (int) someVar - 3;
因此,您必须将结果转换回 (byte) 以使编译器接受分配。
someVar = (byte) (someVar - 3);
【讨论】:
-= 运算符在 IL 级别生成 conv.u1,这就是第一个 sn-p 工作的原因
x op= y 在某些上下文中被评估为x = (T)(x op y)。该规则的存在使得当左操作数的类型为sbyte 时,预定义的运算符可以用作复合运算符、byte、short、ushort 或 char。即使两个参数都是其中一种类型,预定义的运算符也会产生 int 类型的结果,如 §7.3.6.2 中所述。因此,如果没有强制转换,就无法将结果分配给左操作数。”
这是 CLI 规范 (Ecma 335) 中的一个表的副本,它指定了哪些操作数对 A op B 类型的二进制数字运算符有效,其中 A 和 B 是操作数,“op”是运算符,就像您在 sn-p 中使用的 Opcodes.Sub 一样:
这里需要一些注释:
注意F 的行和列,两个操作数都必须是浮点数,不能直接将int 加到double 中。 C# 编译器通过自动将 int 操作数转换为 double 以使运算符有效来处理该限制。
与您的问题相关:另请注意,不存在 byte、sbyte、char、short 和 ushort 类型。同样的方法,编译器将操作数转换为可以表示值的最小类型,以便可以使用运算符。这将是 int32。根据表格,运算结果为int32。
现在问题来了:结果是 int32,但将其分配回字节值需要缩小转换。从 32 位到 8 位。这很麻烦,因为它丢失了重要的位。 C# 编译器要求您明确说明。您基本上承认您知道自己在做什么,并且您知道潜在的令人惊讶的结果。喜欢这个:
byte v = 255;
v = (byte)(v + 1);
-= 运算符是一个问题,因为没有有效的方法来应用所需的强制转换。它在语言语法中是不可表达的。使用 (byte)3 没有意义,文字无论如何都会转换为 int32 以使运算符工作。
他们解决了这个问题,编译器在没有你帮助的情况下自动发出演员表。
【讨论】: