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

Ant*_*y D 4 c# logic byte types bit-manipulation

我有这个代码.

byte dup = 0;
Encoding.ASCII.GetString(new byte[] { (0x80 | dup) });
Run Code Online (Sandbox Code Playgroud)

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

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

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

Encoding.ASCII.GetString(new byte[] { (dup) });
Encoding.ASCII.GetString(new byte[] { (0x80) });
Run Code Online (Sandbox Code Playgroud)

Pav*_*aev 17

这就是C#中的设计方式,事实上,它一直追溯到C/C++ - 后者也提升了操作数int,你通常不会注意到因为int -> char转换是隐含的,而不是C#.这不仅适用于|所有算术和按位操作数,而是适用于所有算术和按位操作数 - 例如,添加两个bytes也会给你一个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中完成的,它会有点无聊,而且它足够好了)虽然规则,所以我们没有理由改变它").


Mar*_*wis 6

文字0x80的类型为"int",因此您不是字节.

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

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