C#中的OR-ing字节给出了int

我有这个代码。

byte dup = 0; Encoding.ASCII.GetString(new byte[] { (0x80 | dup) }); 

当我尝试编译时,我得到:

无法将类型’int’隐式转换为’byte’。 存在显式转换(您是否错过了演员?)

为什么会这样? 不应该| 两个字节给一个字节? 以下两项工作,确保每个项目都是一个字节。

 Encoding.ASCII.GetString(new byte[] { (dup) }); Encoding.ASCII.GetString(new byte[] { (0x80) }); 

这就是C#中的设计方式,事实上,它一直追溯到C / C ++ – 后者也将操作数提升为int ,你通常不会注意到因为int -> char转换有隐含的,而它是不在C#中。 这不仅适用于| 或者,但是对于所有算术和按位操作数 – 例如,添加两个byte s也会给你一个int 。 我在这里引用规范的相关部分:

对于预定义的+, – ,*,/,%,&,|,^,==,!=,>,<,> =和<=二元运算符的操作数,会发生二进制数字提升。 二进制数字促销隐式地将两个操作数转换为公共类型,在非关系运算符的情况下,它也成为操作的结果类型。 二进制数字促销包括按照它们在此处显示的顺序应用以下规则:

  • 如果任一操作数的类型为十进制,则另一个操作数将转换为十进制类型,否则如果另一个操作数的类型为float或double,则会发生编译时错误。

  • 否则,如果任一操作数的类型为double,则另一个操作数将转换为double类型。

  • 否则,如果任一操作数的类型为float,则另一个操作数将转换为float类型。

  • 否则,如果任一操作数的类型为ulong,则另一个操作数将转换为ulong类型,否则如果另一个操作数的类型为sbyte,short,int或long,则会发生编译时错误。

  • 否则,如果任一操作数的类型为long,则另一个操作数将转换为long类型。

  • 否则,如果任一操作数的类型为uint而另一个操作数的类型为sbyte,short或int,则两个操作数都将转换为long类型。

  • 否则,如果任一操作数的类型为uint,则另一个操作数将转换为类型uint。

  • 否则,两个操作数都将转换为int类型。

我不知道这个的确切理由,但我可以考虑一个。 特别是对于算术运算符,人们将(byte)200 + (byte)100突然等于44可能有点令人惊讶,即使在仔细考虑所涉及的类型时它是有意义的。 另一方面, int通常被认为是对大多数典型数字的算术“足够好”的类型,因此通过将两个参数都提升为int ,对于大多数常见情况,您会得到一种“正常工作”行为。

至于为什么这个逻辑也适用于按位运算符 – 我想这主要是为了保持一致性。 它产生一个简单的规则,对所有非布尔二进制类型都是通用的。

但这都是猜测。 Eric Lippert可能是至少要问这个C#决定的真正动机的人(尽管如果答案只是“它是如何在C / C ++和Java中完成的,它会有点无聊,而且它足够好了)虽然规则,所以我们认为没有理由改变它“)。

文字0x80的类型为“int”,因此您不是字节。

您可以将它传递给byte []只能起作用,因为0x80(作为文字)它在字节范围内。

编辑 :即使0x80被强制转换为一个字节,代码仍然无法编译,因为oring字节仍然会给int。 为了让它编译,结果或必须强制转换:( (byte)(0x80|dup)

 byte dup = 0; Encoding.ASCII.GetString(new byte[] { (byte)(0x80 | dup) }); 

两个字节上的按位Or(|)的结果始终为int。