英文:
Why is `flags &= (ushort)~Mask;` problematic when `Mask` is `const`?
问题
以下是翻译的内容:
以下代码引发了编译错误 CS0221:*常量值 '-2' 无法转换为 'ushort'(使用 'unchecked' 语法来覆盖)*
private ushort _fooFlags = 0;
public void SetFoo1Flag(bool foo)
{
const ushort Foo1Mask = 0x0001;
if (foo)
{
_fooFlags |= Foo1Mask;
}
else
{
_fooFlags &= (ushort)~Foo1Mask; // CS0221 错误
}
}
如提示所示,使用 unchecked
修复了此问题。
private ushort _fooFlags = 0;
public void SetFoo1Flag(bool foo)
{
const ushort Foo1Mask = 0x0001;
if (foo)
{
_fooFlags |= Foo1Mask;
}
else
{
unchecked
{
_fooFlags &= (ushort)~Foo1Mask;
}
}
}
我主要是一个C语言编程者,因此我尝试了各种变化来了解这些(基本的)整数操作的行为。
移除 const
是可以的...
public void SetFoo2Flag(bool foo)
{
ushort Foo2Mask = 0x0001;
if (foo)
{
_fooFlags |= Foo2Mask;
}
else
{
_fooFlags &= (ushort)~Foo2Mask;
}
}
...同样,用 const
替换为 readonly
也可以。
private readonly ushort Foo3Mask= 0x0004;
public void SetFoo3Flag(bool foo)
{
if (foo)
{
_fooFlags |= Foo3Mask;
}
else
{
_fooFlags &= (ushort)~Foo3Mask;
}
}
我使用了显式转换,因此我期望 (ushort)~Foo1Mask
成为 ushort
,而不管 ~Foo1Mask
发生了什么。
const
有何不同之处,以至于需要特殊处理,而另外两个(在我看来)相似的变化按我所期望的方式工作?
附注:我知道在这个示例中,我本可以使用枚举和 [Flags]
。
英文:
The following code throws a compiler error CS0221: Constant value '-2' cannot be converted to a 'ushort' (use 'unchecked' syntax to override)
private ushort _fooFlags = 0;
public void SetFoo1Flag(bool foo)
{
const ushort Foo1Mask = 0x0001;
if (foo)
{
_fooFlags |= Foo1Mask;
}
else
{
_fooFlags &= (ushort)~Foo1Mask; // CS0221 error
}
}
As the hint suggests, using unchecked
fixes this issue.
private ushort _fooFlags = 0;
public void SetFoo1Flag(bool foo)
{
const ushort Foo1Mask = 0x0001;
if (foo)
{
_fooFlags |= Foo1Mask;
}
else
{
unchecked
{
_fooFlags &= (ushort)~Foo1Mask;
}
}
}
I'm primarily a C coder, so I tried variations to see how these (basic) integer operations behave.
Removing const
works fine..
public void SetFoo2Flag(bool foo)
{
ushort Foo2Mask = 0x0001;
if (foo)
{
_fooFlags |= Foo2Mask;
}
else
{
_fooFlags &= (ushort)~Foo2Mask;
}
}
..as well as replacing const
with readonly
.
private readonly ushort Foo3Mask= 0x0004;
public void SetFoo3Flag(bool foo)
{
if (foo)
{
_fooFlags |= Foo3Mask;
}
else
{
_fooFlags &= (ushort)~Foo3Mask;
}
}
I'm using an explicit cast, so I'd expect (ushort)~Foo1Mask
to become a ushort
, regardless of what happens with ~Foo1Mask
.
What makes const
so different, that it requires special treatment, while the other two (in my view) similar variations work as I have expected?
PS: I know in this example I could've used an enum and [Flags]
.
答案1
得分: 1
The ~
operator is supported for the following types: "int, uint, long, and ulong" as per the documentation. There's an implicit conversion from ushort
to all of those, but int
is the "smallest" of those types, so it "wins" the fight and becomes the type of ~anyUshortExpression
.
An operation can also be performed at compile time when the expression involves entirely literals, constants, or other expressions that can be resolved at compile time. This means that ~Foo1Mask
will be treated identically to the compiler as if you'd have written -2
. Which is why you see that in the compiler error you get.
As far as why you only see it when you use a constant, if you don't, then at compile time it has no idea that the int
that you're trying to cast to a ushort
won't fit inside of a ushort
. It can't know that until runtime when it actually tries to execute the cast (at which point it will throw in a checked context or wrap around in an unchecked context). So it just takes your word for it at compile time, even in a checked context, since it has no other choice.
英文:
The ~
operator is supported for the following types: "int
, uint
, long
, and ulong
" as per the documentation. There's an implicit conversion from ushort
to all of those, but int
is the "smallest" of those types, so it "wins" the fight and becomes the type of ~anyUshortExpression
.
An operation can also be performed at compile time when the expression involves entirely literals, constants, or other expressions that can be resolved at compile time. This means that ~Foo1Mask
will be treated identically to the compiler as if you'd have written -2
. Which is why you see that in the compiler error you get.
As far as why you only see it when you use a constant, if you don't, then at compile time it has no idea that the int
that you're trying to cast to a ushort
won't fit inside of a ushort
. It can't know that until runtime when it actually tries to execute the cast (at which point it will throw in a checked context or wrap around in an unchecked context). So it just takes your word for it at compile time, even in a checked context, since it has no other choice.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论