有人能指出我,为什么在这里:
Byte b = 100;
b = (Byte)(b+200);
我必须使用显式类型转换。但是这里
Byte b = 100;
b += 200;
我不需要这样做吗?
编译器是否为这两种情况生成不同的IL代码?哪种情况更好?
答案 0 :(得分:15)
因为标准允许(见下面的第二种情况):
14.14.2化合物分配
表单
x
op=
y
的操作是通过应用二元运算符重载决策(第14.2.4节)来处理的,就好像操作是撰写x
opy
。然后,
如果所选运算符的返回类型可隐式转换为
x
类型,则操作将评估为x = x
opy
,但x
仅评估一次。否则,如果所选运算符是预定义运算符,则所选运算符的返回类型可明确转换为
x
类型,并且y
可隐式转换为类型x
或运算符是移位运算符,然后操作被评估为x = (T)(x
opy)
,其中T
是类型x
,但x
仅评估一次。- 否则,复合赋值无效,并发生编译时错误。
在这种情况下,IL代码应该基本相同。当然,如果评估b
有副作用,它将在b = (byte)b + 200
案例中评估两次,在使用化合物分配时仅评估一次。
答案 1 :(得分:6)
这是C#标签中的常见问题解答,很难找到重复内容。首先需要演员阵容。根本原因是CLI仅为Opcodes.Add IL指令指定了有限数量的有效类型。仅支持Int32,Int64,Single,Double和IntPtr类型的操作数。 IntPtr也很特别,C#语言禁止使用那个。
因此C#编译器有使用隐式转换将字节提升为运算符支持的类型。它将选择Int32作为最接近的兼容类型。添加的结果是Int32。在不截断结果的情况下,它不适合返回一个字节,丢掉额外的位。一个明显的例子是255 + 1,Int32中的结果是256但是不适合字节并且在存储时产生0。
这是一个问题,语言设计者不喜欢在没有你明确承认你意识到后果的情况下发生截断。需要使用强制转换来说服编译器您知道。当然,你可能会在没有思考后果的情况下机械地生成演员阵容。但这使它成为你的问题,而不是微软的:)。
rub是+ =运算符,是一个非常好的运算符来编写压缩代码。类似于 var 关键字的简洁性。岩石和坚硬的地方然而,你把演员放在哪里?它只是不起作用,所以他们惩罚问题,并允许截断没有演员。
值得注意的是VB.NET的工作方式,它不需要强制转换。但它保证了C#默认不提供,当结果不适合时会产生OverflowException。非常好,但该检查不是免费的。
设计干净的语言是一个非常难的问题。 C#团队做得非常出色,但不能承受瑕疵。否则是处理器设计带来的那种疣。 IL具有这些类型限制,因为这也是真正的32位处理器,特别是90年代流行的RISC设计。它们的内部寄存器只能处理32位整数和IEEE-754浮点。并且只允许较小类型的装载和存储。 Intel x86内核非常受欢迎,实际上允许在较小类型上进行基本操作。但这主要是一个历史性事故,因为英特尔通过8位8080和16位8086代保持设计兼容。它不是免费的,16位操作需要额外的cpu周期。要避免。
答案 2 :(得分:0)
这是因为隐式转换规则。
当您有二进制+
运算符时,结果将转换为两种类型中较大的一种。
文字200
的类型为int,因此表达式b+200
的类型为int。
赋值运算符=
不执行隐式转换,而是抛出错误。如在
int x = 10;
Byte b = x; //Error
在第二种情况下,+=
运算符需要字节,所以200(其类型为int,但适合字节)被隐式转换为byte,因为编译器知道它可以。以下内容不会编译,因为编译不知道x是否适合一个字节。
Byte b = 100;
int x = 200;
b += x; //Error
如果你使x成为const然后编译:
Byte b = 100;
const int x = 200;
b += x; //OK
答案 3 :(得分:0)
规范将此视为复合赋值运算符的特定情况:
http://msdn.microsoft.com/en-us/library/aa691316%28v=vs.71%29.aspx
具体来说,子弹2:
上面的第二条规则允许将x op = y计算为x =(T)(x op y)在某些情况下。该规则存在于预定义的 当左操作数为时,运算符可用作复合运算符 类型为sbyte,byte,short,ushort或char。即使是两个论点 属于这些类型之一,预定义的运算符产生结果 类型为int,如第7.2.6.2节所述。因此,没有一个演员 无法将结果分配给左操作数。