Recipe 4.6 Determining Whether One or More Enumeration Flags Are Set
Problem
You need to determine whether a
variable of an enumeration type, consisting of bit flags, contains
one or more specific flags. For example, given the following
enumeration Language:
[Flags]
enum Language
{
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008
}
Determine, using Boolean logic, whether the variable
lang in the following line of code contains a
language such as Language.CSharp and/or
Language.Cpp:
Language lang = Language.CSharp | Language.VBNET;
Solution
To determine whether a variable contains a single bit flag that is
set, use the following conditional:
if((lang & Language.CSharp) == Language.CSharp)
{
// lang contains at least Language.CSharp
}
To determine whether a variable exclusively contains a single bit
flag that is set, use the following conditional:
if(lang == Language.CSharp)
{
// lang contains only the Language.CSharp
}
To determine whether a variable contains a set of bit flags that are
all set, use the following conditional:
if((lang & (Language.CSharp | Language.VBNET)) ==
(Language.CSharp | Language.VBNET))
{
// lang contains at least Language.CSharp and Language.VBNET
}
To determine whether a variable exclusively contains a set of bit
flags that are all set, use the following conditional:
if((lang | (Language.CSharp | Language.VBNET)) ==
(Language.CSharp | Language.VBNET))
{
// lang contains only the Language.CSharp and Language.VBNET
}
Discussion
When enumerations are used as bit flags (these enumerations should be
marked with the Flags attribute) they usually will
require some kind of conditional testing to be performed. This kind
of conditional testing requires the use of the bitwise AND
(&) and OR
(|) operators.
Testing for a variable having a specific bit flag set is done with
the following conditional statement:
if((lang & Language.CSharp) == Language.CSharp)
where lang is of the Language
enumeration type.
The & operator is used with a bitmask to
determine whether a bit is set to 1. The result of
ANDing two bits is 1 only when
both bits are 1; otherwise, the result is
0. We can use this operation to determine if a
specific bit flag is set to a 1 in the number
containing the individual bit flags. If we AND the
variable lang with the specific bit flag we are
testing for (in this case Language.CSharp), we can
extract that single specific bit flag. The expression (lang
& Language.CSharp) is solved in the
following manner if lang is equal to
Language.CSharp:
Language.CSharp 0001
lang 0001
ANDed bit values 0001
If lang is equal to another value such as
Language.VBNET, the expression is solved in the
following manner:
Language.CSharp 0001
lang 0010
ANDed bit values 0000
Notice that ANDing the bits together returns the
value Language.CSharp in the first expression and
0x0000 in the second expression. Comparing this
result to the value we are looking for
(Language.CSharp) tells us whether that specific
bit was turned on.
This method is great for checking specific bits, but what if you
wanted to know if only a specific bit was turned on (and all other
bits turned off) or off (and all other bits turned on)? To test
whether only the Language.CSharp bit is turned on
in the variable lang, we can use the following
conditional statement:
if(lang == Language.CSharp)
Consider the situation if the variable lang
contained only the value Language.CSharp. The
expression using the OR operator would look like
this:
Language.CSharp 0001
lang 0001
ORed bit values 0001
Now, add a language value or two to the variable
lang and perform the same operation on
lang:
Language.CSharp 0001
lang 1101
ORed bit values 1101
The first expression results in the same value as we are testing
against. The second expression results in a much larger value than
Language.CSharp. This result indicates that the
variable lang in the first expression only
contains the value Language.CSharp and the second
expression contains other languages including
Language.CSharp.
Using this same formula, we can test multiple bits to determine
whether they are both on and all other bits are off. This is done in
the following conditional statement:
if((lang & (Language.CSharp | Language.VBNET)) ==
(Language.CSharp | Language.VBNET))
Notice that to test for more than one language, we simply
OR the language values together. By switching the
first & operator for an |
operator, we can determine whether at least these bits are turned on.
This is done in the following conditional statement:
if((lang | (Language.CSharp | Language.VBNET)) ==
(Language.CSharp | Language.VBNET))
When testing for multiple enumeration values, it may be beneficial to
add a value to your enumeration, which ORs
together all the values you want to test for. If we wanted to test
for all languages except Language.CSharp, our
conditional statement(s) would grow quite large and unwieldy. To fix
this, we could add a value to the Language
enumeration that ORs together all languages except
Language.CSharp. The new enumeration would look
like this:
[Flags]
enum Language
{
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008,
AllLanguagesExceptCSharp = VBNET | VB6 | Cpp
}
and our conditional statement might look similar to the following:
if((lang | Language.AllLanguagesExceptCSharp) ==
Language. AllLanguagesExceptCSharp)
This statement is quite a bit smaller and is easier to manage and
read.
 |
Use the AND operator when testing whether one or
more bits are set to 1. Use the
OR operator when testing whether one or more bits
are set to 0.
|
|
|