C#中针对const byte字段的位取反

3
我发现,如果我有一个类型为“byte”的字段或变量,我可以对其应用位非(~)并将其转换为byte。但是,如果该字段是“const byte”,我仍然可以应用位非(~),但我不能将其转换为byte。例如,
此代码可以编译:
class Program
{
    byte b = 7;
    void Method()
    {
        byte bb = (byte) ~b;
    }
}

但是这个代码会出现编译错误("常量值'-8'无法转换为'byte'"):
class Program
{
    const byte b = 7;
    void Method()
    {
        byte bb = (byte) ~b;
    }
}

我想知道为什么?


1
在第一种情况下,变量不是const,因此位运算将在运行时执行 - 然后您将收到异常。我认为在第二种情况下,编译器希望在编译时用位运算替换该值(因为b是“const”,所以其值不会改变 - 那么为什么要在运行时浪费资源?),因此它会给出编译时错误。 - user2160375
@pwas,除非使用/checked编译程序,否则您将不会收到异常,这绝对不是正常情况。 - Sam Harwell
@280Z28 你是对的,/checked 默认是关闭的。 - user2160375
3个回答

3
因为 ~ 运算符仅预定义为 int uint long ulong 。 你的第一个示例将 b 隐式转换为 int ,执行否定操作,然后显式转换回一个字节。
在第二个示例中,b是一个常量,因此编译器也会内联否定操作,有效地创建一个值为-8(带符号的二进制补码表示7的负数)的常量 int 。由于一个常量的负值不能被强制转换为 byte (除非添加 unchecked 上下文),所以会出现编译错误。
为避免该错误,请将结果存储在非常量 int 变量中:
const byte b = 7;

void Main()
{
    int i = ~b;
    byte bb = (byte)i;
}

1

byte类型中没有定义位反操作符~,但是int有此操作符。在进行位反操作时,byte类型会被隐式转换成一个int类型,然后再执行位反操作。由此得到的int类型不在byte类型的范围内(0-255,包括边界值),因此只能通过未经检查的转换来将其转换为byte类型。

byte bb = unchecked((byte)~b);

第二个程序无法编译,因为由于使用了编译时常量,它能够在编译时验证不正确的转换。针对非编译时常量值,编译器无法作出此断言。

但这并没有解释const和非const之间的区别。第一个程序可以编译和运行,没有问题,结果是248(7的倒数)。 - Nathan A
@NathanA 似乎编译器规范中的有效“byte”常量与可以显式转换为“byte”的有效整数值不同(这完全超出了语言规范的范围)。 - Servy

0

我无法解释它们之间的区别,但是你第二个程序的简单解决方案是将其标记为未选中状态,如下所示:

byte bb = unchecked((byte)~b);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接