没有强制转换的情况下,两个字节变量的C#XOR将无法编译

Ash*_*Ash 31 c# operators

为什么以下引发编译时错误:'无法将类型'int'隐式转换为'byte':

        byte a = 25;
        byte b = 60;

        byte c = a ^ b;
Run Code Online (Sandbox Code Playgroud)

如果我使用算术运算符,这将是有意义的,因为a + b的结果可能大于可以存储在单个字节中的结果.

然而,将其应用于XOR运算符毫无意义.这里是一个按位操作,它永远不会溢出一个字节.

在两个操作数周围使用转换:

byte c = (byte)(a ^ b);
Run Code Online (Sandbox Code Playgroud)

Mic*_*urr 25

我不能给你理由,但我可以告诉为什么编译器从编译器必须遵循的规则的角度来看这种行为(这可能不是你真正知道的那样).

从C#规范的旧版本(我应该下载更新的版本),重点补充说:

14.2.6.2二进制数字促销本条款内容丰富.

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

  • 如果任一操作数的类型为十进制,则另一个操作数将转换为十进制类型,否则如果另一个操作数的类型为float或double,则会发生编译时错误.
  • 否则,如果任一操作数的类型为double,则另一个操作数将转换为double类型.
  • 否则,如果任一操作数的类型为float,则另一个操作数将转换为float类型.
  • 否则,如果任一操作数的类型为ulong,则另一个操作数将转换为ulong类型,否则如果另一个操作数的类型为sbyte,short,int或long,则会发生编译时错误.
  • 否则,如果任一操作数的类型为long,则另一个操作数将转换为long类型.
  • 否则,如果任一操作数的类型为uint而另一个操作数的类型为sbyte,short或int,则两个操作数都将转换为long类型.
  • 否则,如果任一操作数的类型为uint,则另一个操作数将转换为类型uint.
  • 否则,两个操作数都将转换为int类型.

因此,基本上小于a的操作数int将转换int为这些运算符(并且结果将int是非关系运算符的结果).

我说我不能给你一个理由; 但是,我会猜测一下 - 我认为C#的设计者希望确保在缩小时可能会丢失信息的操作需要让程序员以演员表的形式明确缩小操作.例如:

byte a = 200;
byte b = 100;

byte c = a + b;  // value would be truncated
Run Code Online (Sandbox Code Playgroud)

虽然在两个字节操作数之间执行xor操作时不会发生这种截断,但我认为语言设计者可能不希望有一组更复杂的规则,其中某些操作需要显式转换而其他操作则不需要.


只是一个小小的注释:上面的引用是'信息'而不是'规范',但它以易于阅读的形式涵盖了所有案例.严格来说(在规范意义上),^运算符以这种方式运行的原因是因为在处理byte操作数时该运算符的最近重载是(来自14.10.1"整数逻辑运算符"):

int operator ^(int x, int y); 
Run Code Online (Sandbox Code Playgroud)

因此,正如信息文本所解释的那样,操作数被提升int并产生int结果.