移除枚举标志位

6

老实说,枚举标志被移除的做法让我有些困惑。

举个例子,假设我们有一个枚举类型如下:

[Flags]
enum Letter 
{
    A = 1, // 1
    B = 2, // 10
    C = 4  // 100
}

现在,如果我想让一个变量持有标志Letter.AB,我可以这样做foo = Letter.A | Letter.B。现在这对我来说是有意义的,我可以计算它并且它会有意义:
   01
OR 10
 = 11 = 3 = 1 + 2 = A + B = AB

当涉及到移除标记时,我感到困惑。然而,直觉告诉我应该使用XOR运算符来做这件事,就像这样:

bar = Letter.A | Letter.B | Letter.C // Set bar to ABC
// Now let's remove everything but Letter.C
bar = bar ^ (Letter.A | Letter.B)

手动计算应该得到以下结果:
    111
XOR 011
  = 100 = 4 = C = ABC - (A + B) = 7 - (1 + 2)

但是,当人们移除枚举标志时,他们似乎并不会使用异或运算符,而是使用完全没有意义的运算符。对于使用异或运算符来移除枚举标志,是否存在任何缺点?显然,我没有看到这里的问题,因此一个详细的澄清将非常受欢迎! :)

1
XOR是一种切换操作,因此在执行它之前,您必须确保A和B已被设置 - 否则您可能正在设置它们!使用掩码的AND运算可以让您将不需要的内容归零,从而留下其他所有内容。 - n8wrl
1个回答

19

是的,XOR运算符的问题在于,除非您知道已经获得了所有其他标志,否则它将翻转它们。因此,您的XOR操作不是“删除所有但C”-而是“切换A和B的值”。(因此,如果输入为“A,C”,您最终会得到“B,C”,例如。)

&被使用是因为它可以进行掩码操作。基本思想是,您获得一个仅包含所需位的值,然后将该值与输入值进行按位AND运算进行掩码。

要删除特定标志(而不是保留该特定标志),通常会使用~运算符创建“除该标志外的所有标志”的掩码。例如:

var mask = ~Letter.A;
var newValue = originalValue & mask; // All previous values other than A

使用AND操作符,如果存在该值,则只会检索该值,否则不返回任何内容。我必须承认我不确定~运算符的作用。 - Overly Excessive
1
@OverlyExcessive:它对值的每个位执行此操作(这是一种按位运算符)。听起来你应该复习一下按位运算符的教程(或书籍内容),并尝试各种选项,直到你理解为止。 - Jon Skeet

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