为什么使用flags + bitmasks而不是一系列布尔?

时间:2009-09-10 17:12:13

标签: c# enums flags

鉴于我有一个可能处于一个或多个真/假状态的对象的情况,我总是有点模糊为什么程序员经常使用标志+位掩码而不是仅仅使用几个布尔值。

它遍布.NET框架。不确定这是否是最好的示例,但.NET框架具有以下内容:

public enum AnchorStyles
{
    None = 0,
    Top = 1,
    Bottom = 2,
    Left = 4,
    Right = 8
}

因此,给定锚样式,我们可以使用位掩码来确定选择哪个状态。但是,看起来您可以使用AnchorStyle类/结构来完成相同的事情,其中​​为每个可能的值或单个枚举值的数组定义了bool属性。

当然,我的问题的主要原因是我想知道我是否应该使用自己的代码进行类似的练习。

那么,为什么要使用这种方法呢?

  • 减少内存消耗? (它似乎似乎就像消耗少于bools的数组/结构一样)
  • 比结构或数组更好的堆栈/堆性能?
  • 更快的比较操作?更快的价值添加/删除?
  • 编写它的开发人员更方便吗?

10 个答案:

答案 0 :(得分:17)

传统上这是一种减少内存使用的方法。所以,是的,它在C#中已经过时了: - )

作为一种编程技术,它在今天的系统中可能已经过时了,你可以使用一系列bool,但是... ...

比较存储为位掩码的值是快速的。使用AND和OR逻辑运算符并比较生成的2个整数。

它使用相当少的内存。将所有4个示例值放在位掩码中将使用半个字节。使用bool数组,很可能会为数组对象使用几个字节,并为每个bool使用一个长字。如果你必须存储一百万个值,你就会明白为什么一个bitmask版本更好。

管理起来比较容易,你只需要处理一个整数值,而bool数组在数据库中的存储方式会有很大不同。

而且,由于内存布局,每个方面都比数组快得多。它几乎与使用单个32位整数一样快。我们都知道,对于数据操作来说,这个速度一样快。

答案 1 :(得分:12)

  • 可以按任意顺序轻松设置多个标记。

  • 轻松保存并获得0101011系列数据库。

答案 2 :(得分:7)

除此之外,它更容易向位域添加新的位含义而不是向类添加新的布尔值。从一个实例到另一个实例,比一系列布尔值更容易复制位域。

答案 3 :(得分:6)

它还可以使方法更清晰。想象一个方法,10个bool对比1个Bitmask。

答案 4 :(得分:3)

实际上,它可以有更好的性能,主要是因为你的枚举来自一个字节。 在这种极端情况下,每个枚举值将由一个字节表示,包含所有组合,最多256个。拥有这么多可能的布尔组合将导致256个字节。

但即便如此,我认为这不是真正的原因。我更喜欢那些的原因是C#给我处理这些枚举的力量。我可以用一个表达式添加几个值。我也可以删除它们。我甚至可以使用枚举使用单个表达式一次比较多个值。使用布尔值,代码可以变得更加冗长。

答案 5 :(得分:3)

我建议永远不要使用枚举标志,除非你正在处理一些非常严重的内存限制(不太可能)。您应该始终编写为维护而优化的代码。

拥有多个布尔属性可以更容易地阅读和理解代码,更改值,并提供智能感知评论,更不用说减少错误的可能性。如有必要,您可以在内部始终使用枚举标志字段,只需确保使用布尔属性公开值的设置/获取。

答案 6 :(得分:3)

Raymond Chen有a blog post on this subject

  

当然,位域保存数据存储器,但是   你必须平衡它   代码大小,可调试性和成本   减少多线程。

正如其他人所说,其时间已基本结束。它仍然很容易做到这一点,因为小小的摆弄是有趣和酷炫的,但它不再更有效率,它在维护方面有严重的缺点,它不能很好地与数据库,并且除非你在一个嵌入式世界,你有足够的记忆。

答案 7 :(得分:2)

从领域模型的角度来看,它只是在某些情况下更好地模拟现实。如果您有三个布尔值,如AccountIsInDefault和IsPreferredCustomer以及RequiresSalesTaxState,那么将它们添加到单个Flags修饰枚举中是没有意义的,因为它们不是同一域模型元素的三个不同值。

但是如果你有一组像这样的布尔值:

 [Flags] enum AccountStatus {AccountIsInDefault=1, 
         AccountOverdue=2 and AccountFrozen=4}

  [Flags] enum CargoState {ExceedsWeightLimit=1,  
         ContainsDangerousCargo=2, IsFlammableCargo=4, 
         ContainsRadioactive=8}

然后能够将账户(或货物)的总状态存储在一个变量中是很有用的......它代表一个域元素,其值可以代表任何可能的状态组合。

答案 8 :(得分:1)

  1. 空间效率 - 1位
  2. 时间效率 - 比特由硬件快速处理。
  3. 语言独立性 - 数据可能由许多不同的程序处理,您不必担心跨不同语言/平台实施布尔值。
  4. 大多数时候,这些都不值得在维护方面进行权衡。但是,有时它很有用:

    1. 网络协议 - 减少消息大小将大大节省
    2. 传统软件 - 一旦我不得不添加一些信息来追踪一些传统软件。
    3. 修改标题的成本:数百万美元和多年的努力。 将信息塞进标头中未使用的2个字节的成本:0。

      当然,访问和操作此信息的代码还有额外的成本,但这些都是由函数完成的,所以一旦你定义了访问器,它就不比使用布尔值那样可维护了。

答案 9 :(得分:0)

这是为了提高速度和效率。基本上你所使用的只是一个int。

if ((flags & AnchorStyles.Top) == AnchorStyles.Top)
{
    //Do stuff
}