【问题标题】:How to remove an item for a OR'd enum?如何删除 OR'd 枚举的项目?
【发布时间】:2011-06-14 06:30:54
【问题描述】:

我有一个像这样的枚举:

public enum Blah
{
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16
}

Blah colors = Blah.RED | Blah.BLUE | Blah.YELLOW;

如何从可变颜色中去除蓝色?

【问题讨论】:

  • 小注:C#中的按位枚举应该得到它上面的[Flags]属性。
  • @Nyerguds,你能解释一下为什么它应该获取属性吗?
  • 它在调试时提供了更好的 IntelliSense 支持,因为它将未知的枚举值识别为现有值的组合。
  • 它还提供了一个更有意义的.ToString() 值。例如RED, BLUE, YELLOW 而不是 22

标签: c# enums


【解决方案1】:

And not它.......................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;

【讨论】:

    【解决方案2】:

    您需要使用“BLUE”的~(补码)&

    补码运算符本质上是反转或“翻转”给定数据类型的所有位。因此,如果您使用 AND 运算符 (&) 和某个值(我们称该值为“X”)和一个或多个设置位的补码(我们称这些位为Q 及其补码@987654326 @),语句 X & ~Q 会从 X 中清除在 Q 中设置的所有位并返回结果。

    所以要删除或清除BLUE 位,请使用以下语句:

    colorsWithoutBlue = colors & ~Blah.BLUE
    colors &= ~Blah.BLUE // This one removes the bit from 'colors' itself
    

    也可以指定多个位清零,如下:

    colorsWithoutBlueOrRed = colors & ~(Blah.BLUE | Blah.RED)
    colors &= ~(Blah.BLUE | Blah.RED) // This one removes both bits from 'colors' itself
    

    或者……

    colorsWithoutBlueOrRed = colors & ~Blah.BLUE & ~Blah.RED
    colors &= ~Blah.BLUE & ~Blah.RED // This one removes both bits from 'colors' itself
    

    总结一下:

    • X | Q 设置位 Q
    • X & ~Q 清除位 Q
    • ~X 翻转/反转X 中的所有位

    【讨论】:

      【解决方案3】:

      其他答案是正确的,但要专门从上面删除蓝色,你会写:

      colors &= ~Blah.BLUE;
      

      【讨论】:

        【解决方案4】:

        认为这可能对像我这样偶然发现这里的其他人有用。

        请注意如何处理可能设置为值 == 0 的任何枚举值(有时,为枚举设置 Unknown 或 Idle 状态会很有帮助)。依赖这些位操作操作会导致问题。

        此外,当您的枚举值是其他 2 的幂的组合时,例如

        public enum Colour
        {
            None = 0,  // default value
            RED = 2,
            BLUE = 4,
            GREEN = 8,
            YELLOW = 16,
            Orange = 18  // Combined value of RED and YELLOW
        }
        

        在这些情况下,这样的扩展方法可能会派上用场:

        public static Colour UnSet(this Colour states, Colour state)
        {
            if ((int)states == 0)
                return states;
        
            if (states == state)
                return Colour.None;
        
            return states & ~state;
        }
        

        还有处理组合值的等效 IsSet 方法(虽然有点笨拙)

        public static bool IsSet(this Colour states, Colour state)
        {
            // By default if not OR'd
            if (states == state)
                return true;
        
            // Combined: One or more bits need to be set
            if( state == Colour.Orange )
                return 0 != (int)(states & state);
        
            // Non-combined: all bits need to be set
            return (states & state) == state;
        }
        

        【讨论】:

        • 在我看来,更简单的解决方案是避免使用 0 作为标志。我通常设置像this 这样的标志枚举。我看不出您如何从指定值为 0 的状态中受益。毕竟,重点是您可以关注程序员友好的名称 (Red, Blue, Green) 而不是基础值,是吗?
        • 拥有一个 noneunknownunset 值 == 0 的条目在许多情况下是一件好事,因为您不能总是假设特定值是默认设置,例如如果您只有红色、蓝色和绿色,您是否将红色作为默认值(例如,枚举创建时的值或用户未修改它的值?)
        • 你不能只设置 Unset = 1 并使用 1, 2, 4, 8 作为你的值吗?如果你需要一个默认值,那就是默认构造函数的用途,对吧?为了便于阅读,我喜欢尽可能保持明确,并且在没有给出值时依赖枚举默认为default(int)0),尽管任何开发人员都可能知道这些信息,但对于反正我的口味。编辑:哦等等,让 Unset = 0 会阻止某些东西成为Unset | Blue
        • 您在编辑 Sinjai 中处于正确的轨道上,保持未设置的值 == 0 实际上可以解决一些问题。一个是您提到的,另一个是如果您取消设置所有枚举值,那么如果“未设置”设置为零,则不需要特殊情况。 (例如,如果你 Red & ~Red 那么你最终得到零,那么你必须有代码来检查这种情况并明确分配 Unset 值)
        • 明白了。您是否经常发现自己处理未设置的标志?
        【解决方案5】:

        xor(^) 呢?

        鉴于您要删除的 FLAG 存在,它会起作用。如果没有,您将不得不使用 &。

        public enum Colour
        {
            None = 0,  // default value
            RED = 2,
            BLUE = 4,
            GREEN = 8,
            YELLOW = 16,
            Orange = 18  // Combined value of RED and YELLOW
        }
        
        colors = (colors ^ Colour.RED) & colors;
        

        【讨论】:

          【解决方案6】:

          你可以用这个:

          colors &= ~Blah.RED; 
          

          【讨论】:

            【解决方案7】:

            为了简化标志枚举并通过避免倍数使其更好地阅读,我们可以使用位移位。 (摘自一篇好文章Ending the Great Debate on Enum Flags

            [FLAG]
            Enum Blah
            {
               RED = 1,
               BLUE = 1 << 1,
               GREEN = 1 << 2,
               YELLOW = 1 << 3
            }
            

            也清除所有位

            private static void ClearAllBits()
            {
                colors = colors & ~colors;
            }
            

            【讨论】:

              【解决方案8】:

              如果你使用鸭脸运算符,你不必用 ~ 反转位

              color ^= Color.Red; // unset Color.Red
              

              color ^= (Color.Red | Color.Blue); // unset both Red and Blue
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-01-23
                • 1970-01-01
                • 1970-01-01
                • 2021-04-08
                • 2021-02-20
                • 2010-09-23
                相关资源
                最近更新 更多