【问题标题】:What Does the [Flags] Attribute Really Do?[Flags] 属性的真正作用是什么?
【发布时间】:2011-08-19 15:59:00
【问题描述】:

应用[Flags] 的真正作用是什么?

我知道它会修改Enum.ToString 的行为,但它还有其他作用吗? (例如不同的编译器或运行时行为等)


编辑:是的,我知道它记录枚举旨在用作按位标志的事实,并且应用它更合乎逻辑位标志。不过,我问的是更多关于具体行为变化的信息,而不是一般的编程实践。

【问题讨论】:

  • @SQLMenace:这只是说明我应该何时应用它以及我应该如何编写代码,而不是它是否会改变任何东西的行为。 :\
  • +1 我已经问过自己很多次了
  • 我希望看到@Eric Lippert 对此发表评论。

标签: c# .net enums flags bitflags


【解决方案1】:

以下是具体的行为差异列表:

  • 将带有 [flags] 的枚举设置为 None 会清除所有标志。
  • HasFlags 方法仅在此属性存在时才有效。
  • 正如 Devio 所说,它改变了 Parse 和 Format 方法的功能。他链接到this article。显然它也会影响调试器中显示的内容。
  • 我认为 [flags] 可能对 web 服务中的代码生成有影响,但是 it appears that this is not the case.
  • 明确地说,允许对任何枚举进行按位运算,无论是否带有 [flags]。但使用它是最佳做法。

更多详情:http://msdn.microsoft.com/en-us/library/ms229062.aspx

【讨论】:

    【解决方案2】:

    如果你问它在底层做了什么,据我所知,它改变了 ToString() 方法,没有别的。

    在.Net 4 下,您可以使用HasFlags-方法来检查特定标志。如果我对 msdn 的解释正确,则必须使用 flags-attribute 才能使用此方法。但我没试过。

    【讨论】:

      【解决方案3】:

      在实践中,我使用的一种用途是指示多种状态。这是一些评估测试结果的代码的简化。测试可以正常,也可以有多种原因导致不正常。这样做的好处是,我有一种方法可以评估测试“正常”,并且该方法能够通过一次返回来指示所有可能的故障条件。可能不是最好的设计,但在这种情况下可以。

      [Flags]
      public enum ResultStatusEnum
      {
          Ok = 0x1,
          SampleInvalid = 0x2,
          DirectionInvalid = 0x4,
          TestIsNotValid = 0x8
      }
      

      你是这样设置的:

      ResultStatusEnum res = ResultStatusEnum.SampleInvalid | ResultStatusEnum.DirectionInvalid;
      

      缺点是检查枚举的值变得很麻烦。这不会(必然)起作用:

      res == ResultStatusEnum.Ok
      

      您必须这样做才能检查:

      ResultStatusEnum.SampleInvalid == (res & ResultStatusEnum.SampleInvalid)
      

      在这种情况下,拥有ResultStatusEnum.Ok & ResultStatusEnum.SampleInvalid 是不合逻辑的,但我只是确保这不是我使用枚举的情况。

      【讨论】:

      • 是的,但如果没有这样装饰,其他语言可能/可能无法正确处理枚举。如果它全部在 C# 中,我想这并不重要。不过,当我看到它时,我期待这种用途。没有它,我不希望看到有点明智的使用。所以对可读性很有帮助。
      • 我猜这取决于您所说的“句柄”是什么意思。他们当然仍然可以以相同的方式对它们进行按位运算,但是根据Charles posted 的说法,他们是否会首先允许它们似乎是一个问题。
      【解决方案4】:

      来自MSDN article:

      有趣的是,当 指定标志,解析和格式化 方法具有高级功能。

      同样,Parse 方法可以 成功解析逗号分隔 像刚刚显示的那样的字符串 正确的数值。

      【讨论】:

      • +1 似乎是迄今为止最好的答案。我不知道它会改变 Parse... 的行为
      【解决方案5】:

      请参阅 David M. Kean 的帖子 here。这似乎是语言互操作问题:

      尽管 C# 很高兴允许用户在没有 FlagsAttribute 的情况下对枚举执行位操作,但 Visual Basic 不允许。因此,如果您要将类型公开给其他语言,那么使用 FlagsAttribute 标记枚举是个好主意;它还清楚地表明枚举的成员旨在一起使用。

      问候

      大卫

      【讨论】:

      • +1 很棒(而且出乎意料)的答案。 :) (虽然我不得不承认,对我来说,“.NET”几乎只是同一种语言的不同形式。不过仍然是一个很好的答案。)
      • 如果您将该帖子的内容复制到您的答案中,您的答案会更好。
      • Hrmm... 我刚刚检查过,VB 不会自动将 [flag] 枚举分配为 2 的幂,正如这篇文章所暗示的那样。它以通常的方式将它们增加 1。
      【解决方案6】:

      Flags 提供了将枚举用于多个值的选项。

      考虑一种情况,您希望针对不同情况使用复选框,但又不想在数据库中创建不同的列。如果您有 20 个复选框,则必须使用 bool 在数据库中创建 20 列。但是使用标志,您可以创建一列并使用该值存储在该列中。在控制台中运行此示例以更好地理解它。

      class Program
      {
          static void Main(string[] args)
          {
              //Set the features that you require for car. Consider it as checked in the UI.
              CarFeatures carFeatures = CarFeatures.AC | CarFeatures.Autopilot| CarFeatures.Sunroof;
      
              //Do the backend logic
              if (carFeatures.HasFlag(CarFeatures.Autopilot))
              {
                  //Show Autopilot cars
              }
              //See the what carfeatures are required
              Console.WriteLine(carFeatures);
              //See the integer value of the carfeatures
              Console.WriteLine((int)carFeatures);
              Console.ReadLine();
          }
      }
      
      [Flags]
      public enum CarFeatures
      {
          AC=1,
          HeatedSeats= 2,
          Sunroof= 4,
          Autopilot= 8,
      }
      

      不同的组合总是会给你一个唯一的编号,c# 会回溯以查找所有标记的内容。

      【讨论】:

        猜你喜欢
        • 2010-11-05
        • 1970-01-01
        • 2017-10-19
        • 1970-01-01
        • 2010-09-05
        • 2013-02-23
        • 2012-09-19
        • 2014-04-26
        • 2015-10-14
        相关资源
        最近更新 更多