为什么在带有含义AND的标志枚举中使用按位OR运算符

时间:2012-09-19 08:23:51

标签: c# .net c#-4.0

这可能是一个简单而简单的问题,但我仍然有点混淆按位OR决定使用的原因。假设我有一个包含四个字段的课程A

class A
{
    private int Field1;
    private static int Field2;
    public int Field3;
    public static int Field4;
}

使用Reflection获取字段:

var fields = typeof (A).GetFields(BindingFlags.Public | BindingFlags.Static);

如果你是Reflection的新手并且不知道如何使用BindingFlags,那么你头脑中最初的逻辑思维就是:

此行将选择所有静态OR公共字段,因为使用了按位OR。你想到的预期结果是:

Field2
Field3
Field4

但是当按下F5时,结果将完全不同,按位OR可用作AND

Field4

为什么不使用可能跟随逻辑思维的按位AND运算符。像这样:

var fields = typeof (A).GetFields(BindingFlags.Public & BindingFlags.Static);

我在MSDN中找到了单词:

  

用于组合标志的按位OR运算在某些情况下可能被认为是一个高级概念,对于简单任务而言并不是必需的。

请允许任何人以简单的方式解释高级概念以便理解吗?

3 个答案:

答案 0 :(得分:25)

请参阅最后的摘要。

答案很长:

按位OR组合枚举标志的位。

示例:

  • BindingFlags.Public的值为16或10000(二进制)
  • BindingFlags.Static的值为8或1000(二进制)

按位OR组合如下:

10000
01000
--
11000  --> 24

按位AND将它们组合起来:

10000
01000
--
00000   --> 0

这是Flags的一个非常基本的概念:
每个值都是2的幂,例如:

  • 1 = 2^0
  • 2 = 2^1
  • 4 = 2^2
  • 8 = 2^3

它们的位表示始终为1,其余为0:

decimal | binary
1       | 0001
2       | 0010
4       | 0100
8       | 1000

使用按位AND组合它们中的任何一个将始终导致0,因为在同一位置没有1。按位AND将导致完整的信息丢失。

另一方面,按位OR将始终产生明确的结果。例如,当你有(二进制)1010(十进制10)时,你知道它原来是8和2.没有其他可能性10可以创建。
正如默认所述,您调用的方法稍后可以使用按位AND运算符提取此信息:

if(10 & 8 == 8) // value 8 was set

在这种情况下,按位OR基本上是将值传输到您正在呼叫的方法的工具。
这种方法对这些值的作用与按位OR的使用无关 它可以内部要求所​​有传递的标志匹配,就像GetFields的情况一样。但它也可能只需要一个传递的标志匹配。

对于您作为来电者,以下内容是等效的:

var requiredFlags = new List<BindingFlags>();
requiredFlags.Add(BindingFlags.Public);
requiredFlags.Add(BindingFlags.Static);
typeof (A).GetFields(requiredFlags);

现在不编译为GetFields不会提供这样的重载,但其含义与代码的含义相同。

总结(TL; DR):

按位AND与布尔AND和无关 按位OR与布尔OR

无关

答案 1 :(得分:2)

标志枚举用于表示一组布尔条件。

在您的示例中,必须满足每个布尔条件才能返回相应的字段。

标志枚举只是符合通常的二进制规则的整数值,因此要设置几个位,必须将表示这些位的值一起OR。

完成此操作后,您将拥有一个标记枚举,并设置相应的位。

您遇到的问题是因为您正在混淆两个不同的概念:为标志枚举构造布尔条件集的方式是一个概念。使用标志枚举(或它代表什么)的方式是一个不同的概念。

前者使用OR来构造一组布尔条件。后者表示每个位代表必须满足的布尔条件。

答案 2 :(得分:1)

GetFields()的实现者选择解释各种ORed标志的组合,这意味着所选标准的AND组合。

这是有道理的,因为如果您不想要额外的过滤器,您可以随时删除标准。