How to remove an item for a OR'd enum?
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 开发者_如何学Ccolors?
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 inX
The other answers are correct, but to specifically remove blue from the above you would write:
colors &= ~Blah.BLUE;
And not
it...............................
Blah.RED | Blah.YELLOW ==
(Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;
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;
}
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;
}
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;
You can use this:
colors &= ~Blah.RED;
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
精彩评论