4

我有这个代码。

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

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

无法将类型“int”隐式转换为“byte”。存在显式转换(您是否缺少演员表?)

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

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

3 回答 3

19

在 C# 中就是这样设计的,事实上,可以追溯到 C/C++ - 后者还将操作数提升为int,您通常不会注意到,因为int -> char转换是隐式的,而 C# 中没有。这不仅适用于|任何一个,而且适用于所有算术和按位操作数 - 例如添加两个bytes 也会给你一个int。我将在此处引用规范的相关部分:

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

  • 如果任一操作数是十进制类型,则另一个操作数将转换为十进制类型,或者如果另一个操作数是浮点或双精度类型,则会发生编译时错误。

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

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

  • 否则,如果任一操作数的类型为 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 中的实现方式,而且已经足够好了,那就有点无聊了)规则,所以我们认为没有理由改变它”)。

于 2009-07-31T20:23:54.467 回答
6

文字 0x80 的类型是“int”,所以你不是 oring 字节。

您可以将它传递给 byte[] 仅适用于 0x80 (作为文字)它在字节范围内。

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

于 2009-07-31T20:18:21.467 回答
4
byte dup = 0;
Encoding.ASCII.GetString(new byte[] { (byte)(0x80 | dup) });

两个字节的按位或 (|) 的结果始终是 int。

于 2009-07-31T20:17:43.700 回答