6

我在 C# 编译器中发现了一个奇怪的情况。为什么需要下面的演员表?

using System;

class Program
{
    private const byte BIT_ZERO_SET = 1;
    private const byte BIT_ONE_SET = 2;
    private const byte BIT_TWO_SET = 4;

    static void Main(string[] args)
    {
        byte b = BIT_ZERO_SET | BIT_ONE_SET;
        Console.WriteLine(b);

        //Does not compile, says needs to cast to int.
        //b = b | BIT_TWO_SET;

        //Compiles...ugly
        b = (byte)(b | BIT_TWO_SET);
        Console.WriteLine(b);

        Console.WriteLine("Press enter.");
        Console.ReadLine();    
    }
}

谢谢。

4

5 回答 5

14

这里的各种答案通常都是正确的,但有很多不同的事实散布在各处。相关要点是:

1) 字节的结果 | byte 是一个 int,因为没有 | 在字节上定义的运算符。

2) 仅涉及整数编译时常量的计算被视为“检查”算术;即编译器验证常量结果没有溢出,以此类推。这个事实的一个令人愉快的结果是,将编译时常量整数分配给较小类型的变量或常量会自动验证常量整数是否适合较小类型。如果是这样,那么在没有显式转换的情况下允许分配。如果没有,则发生编译时错误。(如果要覆盖此行为,请使用“未检查”表达式。)

3) 从 int 类型的非常量表达式到字节的赋值需要强制转换,因为编译器无法知道结果肯定适合字节。

4) 复合赋值运算符会自动将强制类型转换插入操作数类型,作为其操作的一部分,正是为了使 b |= 之类的表达式按您的预期工作。

这四个事实应该可以解释你们指出的所有行为。

于 2009-10-14T21:39:24.840 回答
7

这绝对是奇怪的,但发生的事情,b|BIT_TWO_SET是一个整数的结果。

这有效:b = (byte)(b | BIT_TWO_SET);因为在这种情况下结果是 int 。

此外,您可以使用 : 替换该行b |= BIT_TWO_SET;

于 2009-10-14T18:51:38.627 回答
7

怀疑是行:

byte b = BIT_ZERO_SET | BIT_ONE_SET;

实际上是由 C# 编译器处理为将常量值分配给 b,而不是按位运算 - 它可以这样做,因为表达式的右侧是在编译时完全定义的。

该行:

//b = b | BIT_TWO_SET;

未编译,因为按位 OR 运算符提升其元素并计算为 int,而不是字节。由于它涉及运行时值 (b),它不能像之前的行那样编译成常量赋值,并且需要强制转换。

于 2009-10-14T18:52:55.950 回答
2
        b = (byte)(b | BIT_TWO_SET);

至少在针对 2.0 的 Visual Studio 2008 中,您只需要对其进行编译即可。看来| 将字节提升为 int,您必须再次手动将其降级。

是的...快速通过标准表明 | 返回 int(或 uint 或 long 或 ulong)。

于 2009-10-14T18:54:21.523 回答
1

而不是使用

 b = b | BIT_TWO_SET;

用这个:

 b |= BIT_TWO_SET;

好笑啊。

于 2009-10-14T18:57:22.453 回答