【问题标题】:Using Bitwise operators on flags在标志上使用位运算符
【发布时间】:2010-10-06 12:23:21
【问题描述】:

我有四个标志

Current = 0x1  
Past = 0x2  
Future = 0x4  
All = 0x7

假设我收到了过去和未来的两个标志 (setFlags(PAST | FUTURE))。如何判断Past 是否在其中?同样,我怎么知道Current 不在其中?这样我就不必测试所有可能的组合。

【问题讨论】:

    标签: c# .net bit-manipulation bit-fields


    【解决方案1】:

    如果您希望测试掩码中的所有位都匹配:

    if((value & mask) == mask) {...}
    

    如果您希望测试掩码中的任何单个位匹配:

    if((value & mask) != 0) {...}
    

    当您测试多个事物的值时,差异最为明显。

    测试排除:

    if ((value & mask) == 0) { }
    

    【讨论】:

      【解决方案2】:

      首先 - 使用带有 FlagAttribute 的枚举。这就是它的用途。

      [Flags]
      public enum Time
      {
          None = 0
          Current = 1,
          Past = 2,
          Future = 4
          All = 7
      }
      

      然后测试是这样完成的:

      if ( (x & Time.Past) != 0 )
      

      或者这个:

      if ( (x & Time.Past) == Time.Past )
      

      如果“过去”是标志的组合并且您想全部测试它们,则后者会更好。

      设置是这样的:

      x |= Time.Past;
      

      取消设置是这样的:

      x &= ~Time.Past;
      

      【讨论】:

      • 如果我错了,请纠正我,我认为 1 不适合用作标志值?与任何带有 1 的标志值(& 运算符)一样,结果仍然是 1。
      • @Roylee - 不,这是一个完全正常的标志值。它正好对应一位。考虑一下 - 例如 4 & 1 = 0。
      • 冰。明白了 :) 那么你必须确保其余的标志值集是 2 的幂,对吗?
      • @Roylee - 没错! :) 请注意,“无”和“全部”有点不同——它们本身不是标志,而是标志的组合。我也可以制作PastOrPresent=3,因为1 & 2 = 3。只有为经常一起使用的组合添加这些才有意义。它可以节省打字并避免错误。
      • @Roylee - 哇,见鬼。我打错了。它应该是1 | 2 = 3。 :)
      【解决方案3】:

      您可能还想添加这样的扩展方法

        enum states {
           Current = 0x1,
           Past = 0x2,
           Future = 0x4,
           All = 0x7
        };
      
        static bool Is(this states current, states value) {
           return (current & value) == value;
        }
      

      那么你可以这样做:

       if(state.Is(states.Past)) {
          // Past
       }
      

      【讨论】:

        【解决方案4】:

        如果您使用 .NET 4 或更高版本,我更喜欢这样做,更干净的 imao:

        [Flags]
        public enum Time
        {
            None = 0
            Current = 1,
            Past = 2,
            Future = 4
        }
        
        myProp = Time.Past | Time.Future;
        
        if (myProp.HasFlag(Time.Past))
        {
            // Past is set...
        }
        

        【讨论】:

          【解决方案5】:

          Marc Gravell 和 Vilx- 的答案的附录:

          您的标记枚举不应指定“全部”的数量,它应该只包含您现有的值。这适用于任何计算值。

          [Flags]
          public enum Time
          {
              None = 0,
              Current = 1,
              Past = 2,
              Future = 4,
              All = Current | Past | Future
          }
          

          请注意,Vilx- 删除了十六进制值的使用。这很重要,因为一旦您超过 0x8,您的值将必须符合十六进制。你应该只保留十进制。

          编辑: 我还想补充一点,您可以使用位移而不是十六进制/十进制。

          这看起来像:

          [Flags]
          public enum Time
          {
              None = 0,
              Current = 1,
              Past = 1 << 1, // 2, 10 binary
              Future = 1 << 2, // 4, 100 binary
           // Example = 1 << 3, // 8, 1000 binary
           // Example = 1 << 4, // 16, 10000 binary
              All = Current | Past | Future
          }
          

          【讨论】:

          • 你能用Past = 1 &lt;&lt; Current, Future = 1 &lt;&lt; Past之类的东西代替硬编码的十进制值吗?
          • @Narshe 如果您愿意,可以。从技术上讲,Current 也可以是 Current = 1 &lt;&lt; 0Current = 1 &lt;&lt; None,正如你所说,Past = 1 &lt;&lt; CurrentFuture = 1 &lt;&lt; Past 将像我上面所说的那样工作。
          【解决方案6】:
          if ((flags & PAST) == PAST)
          {
            // PAST is there
          }
          
          if ((flags & CURRENT) != CURRENT)
          {
            // CURRENT is not there
          }
          

          【讨论】:

          • 很遗憾这是错误的(无法编译)...在 C# 中,您需要在 (flags & CURRENT) 周围加上括号
          • @Marc Gravell,你为什么要发布这条评论而不是为那个人编辑帖子?
          【解决方案7】:
          (value & Current) == Current
          

          【讨论】:

            【解决方案8】:

            我认为缺少的是除一个以外的“全部”

            [Flags]
            public enum Time
            {
                None = 0,
                Current = 1,
                Past = 1 << 1, // 2, 10 binary
                Future = 1 << 2, // 4, 100 binary
                All = Current | Past | Future
            }
            

            然后用上面的flags枚举,就可以了

            var notNow= Time&~Time.Current;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-08-09
              • 1970-01-01
              • 2012-10-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多