Problem
An enumeration of valuesisneeded to act asbit flagsthat can be ORed together to create a combination of values (flags) in the enumeration.
Solution
Mark the enumeration with theFlags attribute:
[Flags]
public enum RecycleItems {
None = 0x00, Glass = 0x01, AluminumCans = 0x02, MixedPaper = 0x04, Newspaper = 0x08 }
Using Enumerated Members in a Bit Mask | 813 Combining elements of this enumeration is a simple matter of using the bitwise OR operator (|). For example:
RecycleItems items = RecycleItems.Glass | RecycleItems.Newspaper;
Discussion
Adding theFlagsattribute to an enumeration marksthisenumeration asindividual bit flagsthat can be ORed together. Using an enumeration of flagsisno different than using a regular enumeration type. It should be noted that failing to mark an enumeration with the Flags attribute will not generate an exception or a compile- time error, even if the enumeration values are used as bit flags.
The addition of theFlagsattribute provides you with two benefits. First, if theFlags attribute isplaced on an enumeration, the ToString and ToString("G") methods return a string consisting of the name of the constant(s) separated by commas. Oth- erwise, these two methods return the numeric representation of the enumeration value. Note that theToString("F")method returns a string consisting of the name of the constant(s) separated by commas, regardless of whether this enumeration is marked with theFlagsattribute. For an indication of why thisworksin thismanner, see the"F" formatting type in Table 20-3 in Recipe 20.9.
The second benefit is that when you examine the code and encounter an enumera- tion, you can better determine the developer’sintention for thisenumeration. If the developer explicitly defined thisascontaining bit flags(with theFlagsattribute), you can use it as such.
An enumeration tagged with theFlagsattribute can be viewed asa single value or as one or more valuescombined into a single enumeration value. If you need to accept multiple languages at a single time, you can write the following code:
RecycleItems items = RecycleItems.Glass | RecycleItems.Newspaper;
The variable items isnow equal to the bit valuesof the two enumeration values ORed together. These values ORed together will equal 3, as shown here:
RecycleItems.Glass 0001 RecycleItems.AluminumCans 0010 ORed bit values 0011
The enumeration valueswere converted to binary and ORed together to get the binary value0011or3in base10. The compiler views this value both as two individ- ual enumeration values(RecycleItems.Glass andRecycleItems.AluminumCans) ORed together or as a single value (3).
To determine if a single flag has been turned on in an enumeration variable, use the bitwise AND (&) operator, as follows:
RecycleItems items = RecycleItems.Glass | RecycleItems.Newspaper;
if((items & RecycleItems.Glass) == RecycleItems.Glass)
Console.WriteLine("The enum contains the C# enumeration value");
814 | Chapter 20: Numbers and Enumerations else
Console.WriteLine("The enum does NOT contain the C# value");
Thiscode will display the text “The enum containsthe C# enumeration value.” The ANDing of these two values either will produce zero if the variableitems doesnot contain the value RecycleItems.Glass, or it will produce the value RecycleItems.
Glass ifitemscontains this enumeration value. Basically, ANDing these two values looks like this in binary:
RecycleItems.Glass | RecycleItems.AluminumCans 0011 RecycleItems.Glass 0001 ANDed bit values 0001
This is dealt with in more detail in Recipe 20.14.
In some cases, the enumeration can grow quite large. You can add many other recy- clable items to this enumeration, as shown here:
[Flags]
public enum RecycleItems {
None = 0x00, Glass = 0x01, AluminumCans = 0x02, MixedPaper = 0x04, Newspaper = 0x08, TinCans = 0x10, Cardboard = 0x20, ClearPlastic = 0x40, }
When aRecycleItemsenumeration value is needed to represent all recyclable items, you would have to OR together each value of this enumeration:
RecycleItems items = RecycleItems.Glass | RecycleItems.AluminumCans | RecycleItems.MixedPaper;
Instead of doing this, you can simply add a new value to this enumeration that includes all recyclable items as follows:
[Flags]
public enum RecycleItems {
None = 0x00, Glass = 0x01, AluminumCans = 0x02, MixedPaper = 0x04, Newspaper = 0x08, TinCans = 0x10, Cardboard = 0x20, ClearPlastic = 0x40,
All = (None | Glass | AluminumCans | MixedPaper | Newspaper | TinCans | Cardboard | ClearPlastic)
}
Determining Whether One or More Enumeration Flags Are Set | 815 Now there isa single enumeration value,All, that encompasses every value of this enumeration. Notice that there are two methodsof creating the All enumeration value. The second method is much easier to read. Regardless of which method you use, if individual language elements of the enumeration are added or deleted, you will have to modify theAll value accordingly.
ANonevalue should be provided for all enums even where “none of the above” does not make sense, because it is always legal to assign lit- eral zero to an enum, and because enum variables, which begin their lives as assigned to their default values, start as zero.
Similarly, you can also add values to capture specific subsets of enumeration values as follows:
[Flags]
enum Language {
CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008, CobolNET = 0x000F, FortranNET = 0x0010, JSharp = 0x0020, MSIL = 0x0080,
All = (CSharp | VBNET | VB6 | Cpp | FortranNET | Jsharp | MSIL), VBOnly = (VBNET | VB6),
NonVB = (CSharp | Cpp | FortranNET | Jsharp | MSIL) }
Now you have two extra members in the enumerations, one that encompasses VB- only languages(Languages.VBNETandLanguages.VB6) and one that encompasses non- VB languages.