在 C# 中就是这样设计的,事实上,可以追溯到 C/C++ - 后者还将操作数提升为int
,您通常不会注意到,因为int -> char
转换是隐式的,而 C# 中没有。这不仅适用于|
任何一个,而且适用于所有算术和按位操作数 - 例如添加两个byte
s 也会给你一个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 中的实现方式,而且已经足够好了,那就有点无聊了)规则,所以我们认为没有理由改变它”)。