Chapter 6. Enumerations

Enumerations bridge the gap between numbers and objects. More than a numerical ID, less than a struct, they fill that niche where you want a well-understood name without any extra baggage. You can think of them as (mostly) type-safe constants.

Enumerations also provide type-safe functionality for flags.

Declare an Enumeration

Solution: Enumerations can be defined within namespaces or classes with this syntax:

image

This code declares a BookBinding enumeration containing three values. The first value is None and is often included to indicate the lack of a value.

You can use the enumeration like this:

BookBinding binding = BookBinding.Hardcover;

Declare an Enumeration with Explicit Values

Solution: Simply assign values inside the enumeration. You don’t have to define every value. You can define some of them and the compiler will fill in the rest sequentially.

image

Note

There is nothing preventing you from assigning duplicate values to the enumeration constants. I’m not sure if there is a legitimately useful reason to do this, but it is legal.

Declare Flags as an Enumeration

Solution: In C++, you would #define constants, often at a global level. In C#, you can use enumerations to achieve bit-field flag functionality in a type-safe way. You do need to explicitly set the values to multiples of two, however.

image

You can use the BookGenres enumeration in bit-field operations. To see what [Flags] does, examine the following code and its output:

image

Output:

image

Note that the enumeration with the [Flags] attribute printed out each genre correctly.

Determine if a Flag Is Set

Solution: The standard way of doing this is to use the bitwise & operator:

image

However, .NET 4 introduces the HasFlag() method, which accomplishes the same thing:

bool isVampire = genres.HasFlag(BookGenres.Vampire);

Convert an Enumeration to an Integer (and Vice Versa)

Solution: Enumerations cannot be implicitly converted to integers (and vice versa) like they can in C++. You need to explicitly cast the values.

int value = (int)BookLanguage.English;
BookLanguage lang = (BookLanguage)value;

When converting from integer to an enumeration, make sure you validate the result (see the next section).

Determine if an Enumeration Is Valid

Given the preceding enumeration definition, the following is still valid code:

BookBinding = (BookBinding)9999;

Therefore, you will need to validate enumeration values wherever necessary.

Solution: .NET provides the Enum.IsDefined() method to do this.

image

List Enumeration Values

Solution: To get a list of all defined values for a specific enumeration, call Enum.GetValues(), as shown here:

image

Enum.GetName() returns the same string you would get if you just called ToString() on a value. You can also just call Enum.GetNames() to get all the strings back directly.

Convert a String to an Enumeration

Solution: While Enum does contain a standard Parse() method, this can throw exceptions and requires you to cast the result to the desired enumeration type. Instead, use TryParse(), which is both safe and strongly typed, using generics, as in this code example:

image

Convert a String to a Set of Flags

Solution: Enum.TryParse() also works for flags, and it will handle duplicate values as well, as in this sample:

image

The following output is produced:

image

Attach Metadata to Enums with Extension Methods

Solution: Using extension methods combined with attributes (see Chapter 24, “Reflection and Creating Plugins”), you can add a method to your enumeration to access the values you attached in attributes. For this example, let’s create our own attribute called Culture, which we’ll attach to our BookLanguage enumeration values.

image

Now we’ll modify our enumeration to include these attributes:

image

Finally, we need to add the extension method to access these attributes:

image

Now to test it:

image

The following output is produced:

image

Note

Before adding too much extra data on top of Enum values, make sure that you are not violating their lightweight nature. Consider if you actually need a struct to represent your data (perhaps with the Enum as an ID in the struct).

Enumeration Tips

The following list contains some best practices you should follow when using enumerations:

• If your enumerations must match external values (such as from a database), then explicitly assign a value to each enumeration member.

• Always use [Flags] when you need to combine multiple values into a single field.

• Flag enumerations must have values explicitly assigned that are unique powers of two (1, 2, 4, 8, 16, and so on) to work correctly.

• An enumeration should have a singular name if it is not used as flags, whereas flags should have plural names. See the BookBinding and BookGenres examples earlier in this chapter.

• Define a None value in each enumeration, with value of 0. This is especially important when using [Flags].

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset