Published on System iNetwork (http://systeminetwork.com)
From Many, One: Using Enumerations
By VickiHamende
Created 03/17/2008 - 17:45

By:
Craig Pelkie [1]

Let's say you're writing a program and you need to define a field that could be one of four different values. For example, you might have a field named "Season" to represent the season of the year (spring, summer, fall, winter). How would you represent the seasonal values in your code?

In RPG, you might define the seasonal value as named constants or possibly define an array that contains the values. You can use those same techniques in Visual Basic and C#, but the .NET languages provide another option: enumerations.

Enumerations look like constants and are defined like arrays but can be referenced like properties. If you're not familiar with enumerations, it will only take a few minutes for you to learn how to use them. Once you've seen a few examples, you'll be able to code your own enumerations, and better yet, you'll be able to confidently employ the hundreds of enumerations that are used in the .NET Framework.

The SimplePrinter Example

This month's example is a class that defines a "simple printer." That is, the class contains only a description of the printer type and how it is attached. The Visual Basic version of the Printer class is in Figure 1 [2], and the equivalent C# class is in Figure 2 [3]. There are also tester programs: Figure 3 [4] is the Visual Basic tester, and Figure 4 [5] is the C# tester.

Looking at Figure 1 [6] or Figure 2 [7], locate the Printer.A section, which defines an enumeration named PrinterEnum. You can see that an enumeration is defined using a block structure. The keywords Enum (VB) and enum (C#) indicate that the data being defined is an enumeration.

Inside the block of the enumeration, you simply list the item names that are in the enumeration. By default, the data type of each item in an enumeration is integer and the items are numbered starting at zero.

Now look at Printer.C, where the properties for the Printer class are defined. The property to look at is the Type property, which is defined as being a PrinterEnum data type. That means that when you set the property value, you should set it to one of the PrinterEnum items. The internal variable used to store the property's value is m_Type (Visual Basic) and type (C#).

The constructor for the class is at Printer.D. The first parameter for the constructor is of data type PrinterEnum. So when you create a Printer object, you should pass one of the PrinterEnum values as the first parameter of the constructor.

Now look at Figure 3 [8] or Figure 4 [9], the TestSimplePrinter.A section, where the myPrinter object is created. The first parameter passed to the constructor is expressed as Printer.PrinterEnum.Laser. Taking that apart, you go to the Printer class (Figure 1 [10] or Figure 2 [11]), to the PrinterEnum enumeration (Printer.A), and assign the Laser value.

If you stop right now and look at how enumerations are used, you can see that you can easily tell what value you're assigning as the printer type. Although the actual value of Printer.PrinterEnum.Laser is zero (because it is the first item defined in the enumeration), you'll probably find it preferable to express the parameter as the enumeration value. Before you complain about "too much typing," you should know that Visual Studio provides you with IntelliSense prompting when you start entering the parameter. The IntelliSense prompting shows you the list of items in the enumeration, so you don't need to try to remember the item name or its numeric value.

You can see an example of using the printer type value at TestSimplePrinter.B, which is select or switch construct to test the value. You can literally read the code without having to think about how the value is stored internally. Again, IntelliSense prompting is in effect when you type each of the case statements, so it takes no time at all to type it all in.

Combining Values

As nice as the simple enumeration is, there is another type of enumeration that is even more powerful. You can see an example in Figure 1 [12] and Figure 2 [13] at Printer.B. The AttachmentEnum is defined as a FlagsAttribute enumeration. Note the use of the attribute preceding the definition. A FlagsAttribute enumeration is used when you need to combine values into one result.

For example, my printer supports LAN, parallel, and USB attachments. Rather than define separate properties of the Printer class to contain each of those options (for example, rather than have IsLan, IsParallel, and IsUsb properties), I can define one property named Attachment (see Printer.C) and have that one property contain the combined value.

To make a FlagsAttribute enumeration work, you need to assign unique values to each of its items based on a "power of 2" scheme. It is conventional to assign an item of None or Nothing as the first item in a FlagsAttribute enumeration and explicitly assign it the value 0, as shown in Printer.B. After that, you explicitly assign values to the remaining items, as shown. It is not required that you assign values in ascending order although it is conventional.

The idea with a FlagsAttribute enumeration is that you add the values together. For example, my LAN/Parallel/USB printer can be thought of as having an attachment value of 14 (the sum of the items). If you look at the enumeration itself, there is only one combination of those three items that adds up to 14. For any other combination you choose, there is only one way to add up items to get the number of the combination.

The AttachmentEnum is used for the Attachment property (Printer.C) and in the constructor at Printer.D.

Now look at Figure 3 [14] or Figure 4 [15], TestSimplePrinter.A, where the myPrinter object is created. You can see that the second parameter passed to the constructor is an OR'ing of the three attachment types. At first glance, this code probably won't make any sense; you might just form a notion that it "does something" (hopefully the right thing) and then move on. However, if you look at the operation in terms of bits, it might be easier to see what's happening. Expressed as bits, the value for LAN is b'0010' (2), Parallel is b'0100' (4), and USB is b'1000' (8). When those values are OR'ed together, you get b'1110' (14).

Combining the values together, though, is only half the story. How do you work with something like the Attachment property to determine what types of attachments the printer supports?

The TestSimplePrinter.C section in Figure 3 [16] and Figure 4 [17] shows how you can test a FlagsAttribute enumeration value to determine if it contains one of the items in the FlagsAttribute enumeration. To perform the test, the Attachment property is AND'ed with the FlagsAttribute enumeration value you want to check for, and then the result is compared to 0.

Again, it helps to look at this as bit operations. Assume that the value of the Attachment property is 14 (LAN/Parallel/USB). Now look at the first test in TestSimplePrinter.C. The Attachment property value of 14 (b'1110') is AND'ed with the Printer.AttachmentEnum.BlueTooth item value (b'0001'). In an AND operation, both bits in the corresponding positions must be on for the resulting bit to be on. So b'1110' AND b'0001' yields a result of b'0000'. That result is then compared to zero. If the result is not zero, it means that the Attachment property contained the value being searched for.

Try another example, looking for Printer.AttachmentEnum.LAN. Take the Attachment value (b'1110'), AND it with the value for LAN (b'0010'), and the result is b'0010'. That compares to "not equal" to zero, so the Attachment property contains the LAN attachment type.

E Pluribus, Enum?

Given these simple examples, you can see how to use a simple enumeration and a FlagsAttribute enumeration. You can find many examples of enumerations in the MSDN documentation for the .NET Framework. Items are listed in the documentation with the word "Enumeration" as part of their identification. When you look at the details for an enumeration, it is clearly stated if the enumeration is a FlagsAttribute enumeration.

Once you start using enumerations, you'll probably find many places in your code where you can use them. Any time you're tempted to code a list of values as constants or array elements, stop and think: you might have a good candidate for an enumeration.

Craig Pelkie has worked as a programmer with IBM midrange computers for many years. He has also written and lectured extensively on AS/400 and System i technologies, including client/server programming, Client Access, Java WebSphere, .NET applications for the System i, and web development. You can reach him at craig@web400.com [18].

Copyright © Penton Media

Source URL: http://systeminetwork.com/article/many-one-using-enumerations

Links:
[1] http://systeminetwork.com/author/craig-pelkie
[2] http://pentontech.com/IBMContent/Documents/article/56424_533_Fig1_SimplePrinter.vb.txt
[3] http://pentontech.com/IBMContent/Documents/article/56424_534_Fig2_SimplePrinter.cs.txt
[4] http://pentontech.com/IBMContent/Documents/article/56424_535_Fig3_TestSimplePrinter.vb.txt
[5] http://pentontech.com/IBMContent/Documents/article/56424_536_Fig4_TestSimplePrinter.cs.txt
[6] http://pentontech.com/IBMContent/Documents/article/56424_533_Fig1_SimplePrinter.vb.txt
[7] http://pentontech.com/IBMContent/Documents/article/56424_534_Fig2_SimplePrinter.cs.txt
[8] http://pentontech.com/IBMContent/Documents/article/56424_535_Fig3_TestSimplePrinter.vb.txt
[9] http://pentontech.com/IBMContent/Documents/article/56424_536_Fig4_TestSimplePrinter.cs.txt
[10] http://pentontech.com/IBMContent/Documents/article/56424_533_Fig1_SimplePrinter.vb.txt
[11] http://pentontech.com/IBMContent/Documents/article/56424_534_Fig2_SimplePrinter.cs.txt
[12] http://pentontech.com/IBMContent/Documents/article/56424_533_Fig1_SimplePrinter.vb.txt
[13] http://pentontech.com/IBMContent/Documents/article/56424_534_Fig2_SimplePrinter.cs.txt
[14] http://pentontech.com/IBMContent/Documents/article/56424_535_Fig3_TestSimplePrinter.vb.txt
[15] http://pentontech.com/IBMContent/Documents/article/56424_536_Fig4_TestSimplePrinter.cs.txt
[16] http://pentontech.com/IBMContent/Documents/article/56424_535_Fig3_TestSimplePrinter.vb.txt
[17] http://pentontech.com/IBMContent/Documents/article/56424_536_Fig4_TestSimplePrinter.cs.txt
[18] mailto:craig@web400.com