230

I have an enum like:

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

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

How could I remove the color blue from the variable colors?

Blankman
  • 259,732
  • 324
  • 769
  • 1,199

8 Answers8

419

You need to & it with the ~ (complement) of 'BLUE'.

The complement operator essentially reverses or 'flips' all bits for the given data type. As such, if you use the AND operator (&) with some value (let's call that value 'X') and the complement of one or more set bits (let's call those bits Q and their complement ~Q), the statement X & ~Q clears any bits that were set in Q from X and returns the result.

So to remove or clear the BLUE bits, you use the following statement:

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

You can also specify multiple bits to clear, as follows:

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

or alternately...

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

So to summarize:

  • X | Q sets bit(s) Q
  • X & ~Q clears bit(s) Q
  • ~X flips/inverts all bits in X
David Sherret
  • 101,669
  • 28
  • 188
  • 178
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
58

The other answers are correct, but to specifically remove blue from the above you would write:

colors &= ~Blah.BLUE;
akjoshi
  • 15,374
  • 13
  • 103
  • 121
par
  • 17,361
  • 4
  • 65
  • 80
11

And not it...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;
Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
8

Thought this might be useful for other people that stumbled here like me.

Be careful how you handle any enum values that you might set to have a value == 0 (sometimes it can be helpful to have a Unknown or Idle state for an enum). It causes problems when relying on these bit manipulation operations.

Also when you have enum values that are combinations of other power of 2 values, e.g.

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

In these cases an extension method such as this might come in handy:

public static Colour UnSet(this Colour states, Colour state)
{
    if ((int)states == 0)
        return states;

    if (states == state)
        return Colour.None;

    return states & ~state;
}

And also the equivilent IsSet method that handles the combined values (albeit in a bit of a hacky way)

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;
}
Sverrir Sigmundarson
  • 2,453
  • 31
  • 27
  • It seems to me that the simpler solution is to avoid using 0 as a flag. I typically set up flag enums like [this](https://hastebin.com/futuwetipo.swift). I don't see how you benefit from specifying a state with a value of 0. After all, the whole point is that you can concern yourself with the programmer-friendly names (`Red, Blue, Green`) rather than the underlying values, yeah? – Sinjai Feb 27 '18 at 03:36
  • 1
    Having a `none` or `unknown` or `unset` entry with value == 0 is in many cases a good thing as you can't always assume that a particular value is the default set, e.g. if you only have Red, Blue and Green are you going to have Red as the default value (e.g. the value that the enum has when it is created or the user has not modified it?) – Sverrir Sigmundarson Feb 28 '18 at 08:10
  • Can't you just have Unset = 1 and use `1, 2, 4, 8` as your values? If you need a default value, that's what default constructors are for, right? I like to keep things as explicit as possible for the sake of readability, and relying on an enum to default to `default(int)` (`0`) when not given a value, despite being information presumably known by any developer, is too sneaky for my tastes anyway. Edit: Oh wait, would making Unset = 0 prevent something from being `Unset | Blue`? – Sinjai Feb 28 '18 at 10:28
  • You're on the right track in your edit Sinjai, keeping the unset value == 0 actually solves a few problems. One being what you mentioned and another one being if you unset all enum values then you don't need a special case for "Unset" if it is set to zero. (e.g. if you `Red & ~Red` then you end up with zero you would then have to have code to check for this case and explicitly assign the `Unset` value) – Sverrir Sigmundarson Mar 02 '18 at 19:41
  • Gotcha. Do you often find yourself dealing with unset flags? – Sinjai Mar 02 '18 at 19:53
  • Whenever I'm working on consuming data from a user or external source or working on anything related to a UI this eventually pops up. You often need to know when the value has not been set by the user or the data source reports corrupt or missing data (you may not want to assign defaults in all cases if data is missing) – Sverrir Sigmundarson Mar 02 '18 at 20:25
  • 2
    I know this is old but for your Unset method if `states == 0` then `states & ~state == states` so your first branch is not needed. Likewise if `states == state` then `states & ~state == Colour.None` so your second branch is not needed and you can just return `states & ~state`... – Chris Jul 11 '18 at 16:07
4

To simplify the flag enum and make it may be better to read by avoiding multiples, we can use bit shifting. (From a good article Ending the Great Debate on Enum Flags)

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

and also to clear all bits

private static void ClearAllBits()
{
    colors = colors & ~colors;
}
Matt Allen
  • 492
  • 5
  • 12
3

What about xor(^)?

Given that the FLAG you are trying to remove is there, it will work.. if not, you will have to use an &.

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;
3

You can use this:

colors &= ~Blah.RED; 
Majid gharaei
  • 281
  • 3
  • 11
3

To toggle the flag, you can use the duckface operator, you don't have to invert bits with ~

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

or

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

However, this toggles the flag instead of clearing it.

Edit for correctness, as mentioned by @daniil-palii

Michael
  • 386
  • 2
  • 9