151

我总是很惊讶,即使在使用 C# 这么久之后,我仍然设法找到我不知道的东西......

我已经尝试在互联网上搜索这个,但是在搜索中使用“~”对我来说并不那么好,而且我在 MSDN 上也没有找到任何东西(并不是说它不存在)

我最近看到了这段代码,波浪号(~)是什么意思?

/// <summary>
/// Enumerates the ways a customer may purchase goods.
/// </summary>
[Flags]
public enum PurchaseMethod
{   
    All = ~0,
    None =  0,
    Cash =  1,
    Check =  2,
    CreditCard =  4
}

看到它我有点惊讶,所以我尝试编译它,它起作用了……但我仍然不知道它的含义/作用。有什么帮助吗??

4

10 回答 10

138

~ 是一元补码运算符——它翻转其操作数的位。

~0 = 0xFFFFFFFF = -1

在二进制补码算术中,~x == -x-1

~ 运算符几乎可以在任何从 C 中借用语法的语言中找到,包括 Objective-C/C++/C#/Java/Javascript。

于 2008-12-22T21:38:17.140 回答
60

我认为:

[Flags]
public enum PurchaseMethod
{
    None = 0,
    Cash = 1,
    Check = 2,
    CreditCard = 4,
    All = Cash | Check | CreditCard
 }

会清楚一点。

于 2008-12-22T21:42:59.987 回答
23
public enum PurchaseMethod
{   
    All = ~0, // all bits of All are 1. the ~ operator just inverts bits
    None =  0,
    Cash =  1,
    Check =  2,
    CreditCard =  4
}

由于 C# 中有两个补码,~0 == -1所以二进制表示中所有位均为 1 的数字。

于 2008-12-22T21:37:42.587 回答
17

它比

All = Cash | Check | CreditCard

解决方案,因为如果您稍后添加另一种方法,请说:

PayPal = 8 ,

您将已经使用波浪号-All,但必须更改其他的所有线。所以它以后不容易出错。

问候

于 2008-12-22T22:38:03.887 回答
11

只是一个旁注,当你使用

All = Cash | Check | CreditCard

你有一个额外的好处,它Cash | Check | CreditCard会评估All而不是另一个值 (-1),它不等于 all,同时包含所有值。例如,如果您在 UI 中使用三个复选框

[] Cash
[] Check
[] CreditCard

并对它们的值求和,然后用户将它们全部选中,您将All在生成的枚举中看到。

于 2008-12-22T23:00:36.493 回答
9

对于发现这个问题很有启发性的其他人,我有一个简单的~例子可以分享。以下来自于绘制方法实现的片段,如本 Mono 文档中所详述,使用~效果非常好:

PaintCells (clipBounds, 
    DataGridViewPaintParts.All & ~DataGridViewPaintParts.SelectionBackground);

如果没有~运算符,代码可能看起来像这样:

PaintCells (clipBounds, DataGridViewPaintParts.Background 
    | DataGridViewPaintParts.Border
    | DataGridViewPaintParts.ContentBackground
    | DataGridViewPaintParts.ContentForeground
    | DataGridViewPaintParts.ErrorIcon
    | DataGridViewPaintParts.Focus);

...因为枚举看起来像这样:

public enum DataGridViewPaintParts
{
    None = 0,
    Background = 1,
    Border = 2,
    ContentBackground = 4,
    ContentForeground = 8,
    ErrorIcon = 16,
    Focus = 32,
    SelectionBackground = 64,
    All = 127 // which is equal to Background | Border | ... | Focus
}

注意到这个枚举与 Sean Bright 的答案相似吗?

我认为对我来说最重要的一点~是枚举中的运算符与普通代码行中的运算符相同。

于 2011-11-04T22:01:01.767 回答
5

它是一个补码运算符,这是我经常参考的按位运算符的一篇文章

http://www.blackwasp.co.uk/CSharpLogicalBitwiseOps.aspx

msdn 在他们的枚举文章中也使用了它,这表明它使用得更好

http://msdn.microsoft.com/en-us/library/cc138362.aspx

于 2008-12-22T21:42:52.653 回答
1

我个人使用的替代方法与@Sean Bright 的答案相同,但对我来说看起来更好,是这个:

[Flags]
public enum PurchaseMethod
{
    None = 0,
    Cash = 1,
    Check = 2,
    CreditCard = 4,
    PayPal = 8,
    BitCoin = 16,
    All = Cash + Check + CreditCard + PayPal + BitCoin
}

请注意这些数字的二进制性质,它们都是 2 的幂,如何使以下断言成立:(a + b + c) == (a | b | c). 恕我直言,+看起来更好。

于 2013-02-21T03:05:03.867 回答
1

我对 ~ 做了一些实验,发现它可能有陷阱。考虑一下 LINQPad 的这个片段,它表明当所有值一起进行运算时,All 枚举值的行为不符合预期。

void Main()
{
    StatusFilterEnum x = StatusFilterEnum.Standard | StatusFilterEnum.Saved;
    bool isAll = (x & StatusFilterEnum.All) == StatusFilterEnum.All;
    //isAll is false but the naive user would expect true
    isAll.Dump();
}
[Flags]
public enum StatusFilterEnum {
      Standard =0,
      Saved =1,   
      All = ~0 
}
于 2013-11-15T13:55:37.130 回答
1

[Flags] 枚举中的每个位都表示启用 ( 1) 或禁用 ( 0)。
~运算符用于反转数字的所有位。示例:00001001b变成11110110b.
So~0用于创建启用所有位的值,例如11111111b8 位枚举。

只想补充一点,对于这种类型的枚举,使用按位左移运算符可能更方便,如下所示:

[Flags]
enum SampleEnum
{
    None   = 0,      // 0000b
    First  = 1 << 0, // 0001b
    Second = 1 << 1, // 0010b
    Third  = 1 << 2, // 0100b
    Fourth = 1 << 3, // 1000b
    All    = ~0      // 1111b
}
于 2017-04-04T13:09:10.203 回答