Enumerating the Possibilities
Taking Advantage of the Enum Class
October 30, 2009
Class Act
LANGUAGES: VB
TECHNOLOGIES: Enumerations| Enum class
Enumeratingthe Possibilities
TakingAdvantage of the Enum Class
By Ken Getz
Whendescribing the behavior of an object, it s often useful to provide a list ofpossible options for a specific property. For example, the Calendar control provides a FirstDayOfWeekproperty, and its value can be Default, Sunday, Monday,etc. The TitleFormat property can beeither Month or MonthYear. The Calendar control and many other objects provide groups of integerconstants that indicate how you want properties to behave. These groups arecalled enumerations, and you can create your own in addition to theenumerations the .NET Framework provides.
To makeit possible for you to interact with enumerations programmatically, the .NETFramework provides the Enum class.Besides the methods this class inherits from the base Object class, you ll find the shared methods (or static methods,for C# developers) shown in FIGURE 1. In this article, I ll demonstrate how touse most of these methods in two sample pages. In addition, I ll describe howto create your own enumerations and how to interact with them programmatically.
Method | Description |
---|---|
Format | Format converts an enumerated value to an equivalent string representation by using the supplied format specifier. |
GetName | Given an enumerated value, GetName retrieves the named constant corresponding to the value. |
GetNames | GetNames retrieves an array of strings corresponding to the items in the enumeration, in order by numeric value. |
GetUnderlyingType | GetUnderlyingType retrieves the underlying type of the enumeration (any integral type except Char). |
GetValues | GetValues retrieves an Array object containing all the numeric items in the enumeration. |
IsDefined | IsDefined returns True if an item with the specified value exists within the enumeration. |
Parse | Parse converts from a string representation of one or more items into the corresponding numeric value. This is, effectively, the inverse of the GetName method. |
ToObject | ToObject retrieves an instance of the enumeration, of the specified value. You can get by without this for the most part, except in rare cases in which you require an Object type. (See the SetValue method of the PropertyInfo class in the Reflection namespace for an example of where this might be useful.) |
FIGURE1: Use theseshared methods of the Enum class tointeract with items programmatically.
Working with Names and Values
To makeit possible for you to iterate through an enumeration s names and values, the Enumclass provides two useful methods: GetNames and GetValues. The GetNamesmethod returns an array containing the names in the enumeration, in order bythe values each name represents. The GetValues method returns an arraycontaining all the values in order. (Interestingly, the GetNames methodreturns an array of strings defined as String. The GetValuesmethod returns an array defined as Array. You can t treat these the sameway, as you ll see in the code.)
Imagineyou d like to supply users a drop-down list containing all the items within anenumeration and allow them to choose from the list. For example, the Calendarcontrol provides enumerations defining values for several of its properties,including the FirstDayOfWeek, TitleFormat, and DayFormatproperties. Each of these properties accepts a value from an enumeration withthe same name as the property itself. FIGURE 2 shows a sample page, Calendar.aspx, that demonstrates twodifferent techniques for filling a list control. (The sample uses the DropDownListcontrol, but you could use the same techniques for any control that inheritsfrom the ListControl base class, including the ListBox, CheckBoxList,and RadioButtonList controls.)
FIGURE 2: Use this sample page to test theprocess of filling list controls with values from an enumeration and retrievingthe value once you select an item from the list.
FIGURE 3 shows what the sample page s Page_Load event handler looks like.
Private Sub Page_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
If Not Page.IsPostBackThen
FillListWithEnum1(ddlFirstDayOfWeek, _
GetType(FirstDayOfWeek))
FillListWithEnum1(ddlDayNameFormat, _
GetType(DayNameFormat))
FillListWithEnum2(ddlTitleFormat, _
GetType(TitleFormat))
FillExistingItems()
End If
End Sub
FIGURE3: Calendar.aspx sPage_Load event handler.
The first method, FillListWithEnum1,uses the code shown in FIGURE 4 to do its work.
Private Sub FillListWithEnum1( _
ByVal lc As ListControl, ByVal typ As Type)
If typ.IsEnum Then
lc.Items.Clear()
Dim obj As Object
Dim li As ListItem
For Each obj In System.Enum.GetValues(typ)
li = New ListItem()
li.Text = System.Enum.GetName(typ, obj)
li.Value = CStr(obj)
lc.Items.Add(li)
Next
End If
End Sub
FIGURE 4:The FillListWithEnum1 method.
First,this procedure checks to ensure it was passed an enumeration (by calling the IsEnum method of the System.Type object passed to it). Ifso, the procedure clears the items from the DropDownList control and iterates through each item in the Array object that is returned when youcall the GetValues method:
For Each obj InSystem.Enum.GetValues(typ)
' ...
Next obj
For eachitem in the enumeration, the code creates a new ListItem object and calls the GetNamemethod to retrieve the name corresponding to the selected enumeration item. Thecode fills in the ListItem object s Text and Value properties and adds the ListItemto the control:
li = NewListItem()
li.Text =System.Enum.GetName(typ, obj)
li.Value =CStr(obj)
lc.Items.Add(li)
Note Iused the CStr function here ratherthan calling the ToString method. ToString converts the enumeration iteminto its text representation, the name of the item. What this code requires issimply the numeric value of the item, and the CStr function provides that simple conversion for you.
When youselect an item from the DropDownListcontrol, the page calls the SetFirstDayOfWeekprocedure, which uses this single line of code to do its work:
Calendar1.FirstDayOfWeek = CType( _
ddlFirstDayOfWeek.SelectedItem.Value,FirstDayOfWeek)
Thiscode converts the text in the Valueproperty of the selected ListItemobject into the appropriate enumeration type. Then, the code assigns that textto the FirstDayOfWeek property ofthe Calendar control.
Thesecond method s code is much simpler. It simply binds the control to theresults of calling the enumeration s GetNamesmethod, like this:
Private Sub FillListWithEnum2( _
ByVal lc As ListControl, ByVal typ As Type)
If typ.IsEnum Then
lc.DataSource = System.Enum.GetNames(typ)
lc.DataBind()
End If
End Sub
Notice,however, that this technique doesn t associate numeric values with the listitems. You ll have to find those later when you need them. When you select anitem from the TitleFormat drop-downlist, you run the following code:
Private SubSetTitleFormat()
Dim strValue As String = _
ddlTitleFormat.SelectedItem.Text
Dim typ As System.Type =GetType(TitleFormat)
Calendar1.TitleFormat = _
CType(System.Enum.Parse(typ, strValue),TitleFormat)
End Sub
Thismethod retrieves the selected text from the control and then creates a System.Type object that represents the TitleFormat enumeration type. Toconvert from the named item into an enumerated value, the code calls the Parse method, given the type and thevalue. This method returns an Object,so the code must convert the results into the appropriate type by calling the CType method:
Calendar1.TitleFormat = _
CType(System.Enum.Parse(typ, strValue),TitleFormat)
Browseto the sample page and try out the FirstDayOfWeekand TitleFormat controls. You won tsee any difference. Which technique should you use? I recommend the secondtechnique if you have a choice. It takes a tiny bit longer on each post back tothe page because you have to do a little more work, but the timing isinconsequential. In addition, the page can load a bit faster because there sless code to run when loading the control initially.
Todemonstrate the IsDefined method ofthe Enum class, the sample page alsoincludes a text box that allows you to enter a value for the FirstDayOfWeek property. Enter a value,click the Set button, and this codesets the property for you:
Dim typ As Type= GetType(FirstDayOfWeek)
Dim intValue AsInteger = CInt(txtFirstDayOfWeek.Text)
If System.Enum.IsDefined(typ, intValue) Then
Calendar1.FirstDayOfWeek = _
CType(intValue, FirstDayOfWeek)
Thiscode calls the IsDefined method andpasses in the value returned from the GetTypefunction as well as the number you entered into the text box. If the methodreturns True, the code sets the FirstDayOfWeek property of the calendarafter converting the integer to the correct type.
Enumerations with Multiple Values
Someenumerations, like those used with the Calendarcontrol, only allow you to select a single value logically. Others are meant toallow multiple selections, combined together. For instance, take the Attributes property of a FileInfo object. This property isdefined as an instance of the FileAttributesenumeration, which contains values that can be combined to describe theattributes of a file. (The enumeration contains values such as ReadOnly, Hidden, System, Archive, and so on.) To be able tocombine the items, the value of each item must have been assigned one or morebits within a binary value. That is, if you imagine a 32-bit value representingall the possible attribute combinations added together, each of the enumeratedvalues must uniquely represent one or more of those bits. These enumerationsare often called bitfield enumerations because each value generally representsa single binary bit from a possible group of combinable integer values. FIGURE5 shows the FileAttributesenumerated items and the corresponding value for each. In addition, the figureshows a binary representation of each value. Note that each value contains aunique combination of the possible bits, so they can be combined and stillmaintain all the information about which values have been included.
FileAttributes Item | Decimal Value | Binary Value |
---|---|---|
ReadOnly | 1 | 0000 0000 0000 0001 |
Hidden | 2 | 0000 0000 0000 0010 |
System | 4 | 0000 0000 0000 0100 |
Directory | 16 | 0000 0000 0001 0000 |
Archive | 32 | 0000 0000 0010 0000 |
Device | 64 | 0000 0000 0100 0000 |
Normal | 128 | 0000 0000 1000 0000 |
Temporary | 256 | 0000 0001 0000 0000 |
SparseFile | 512 | 0000 0010 0000 0000 |
ReparsePoint | 1024 | 0000 0100 0000 0000 |
Compressed | 2048 | 0000 1000 0000 0000 |
Offline | 4096 | 0001 0000 0000 0000 |
NotContentIndexed | 8192 | 0010 0000 0000 0000 |
Encrypted | 16384 | 0100 0000 0000 0000 |
FIGURE5: Every itemwithin a bitfield enumeration should have a unique binary representation, socombining values will create a value in which it s possible to determine thesource items that were combined to create it.
The Enum class provides full programmaticsupport for bitfield enumerations. The Formatmethod, for example, allows you to take in a value and convert it to one ofseveral different string formats. FIGURE 6 shows the formatting strings you canuse when calling the Enum.Formatmethod. To try out the method, browse to the sample page BitFieldEnums.aspx andselect a file from the list of files. The SelectedIndexChangedevent-handling code for the list box will display the various formatted valuesin a table on the page, as shown in FIGURE 7.
Format | Description |
---|---|
G or g | Returns the name of the enumerated constant if it exists, or the decimal equivalent, if it doesn t. For the FileAttributes enumeration, specifying 2 returns Hidden. Specifying 3 returns ReadOnly, Hidden. (For enumerations that you create, adding the Flags attribute affects this behavior. More information about the Flags attribute appears later in the article.) |
X or x | Returns the value as a hexadecimal, without a prefix indicating the number base. |
D or d | Returns the value in decimal format. |
F or f | Effectively the same as the G specifier, except that it treats all enumerations as bitfields. More information about the Flags attribute appears later in the article. |
FIGURE6: The Enum.Format method uses these formatspecifiers to determine the formatted output. In each case, the method returnsa string.
FIGURE 7: The sample page,BitFieldEnums.aspx, allows you to work with the built-in FileAttributes enumeration as well as the user-defined SeasonsEnum.
The Format method expects you to supplythree parameters:
A System.Type object representing theenumeration with which you re working. (The samples use the GetType function to convert a type nameinto a Type object.)
Aninstance of the enumerated type containing the value you want displayed.
Aformatting specifier selected from the items in FIGURE 6.
The sample page uses the code in FIGURE 8 to display the list offiles.
Private Sub Page_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
If Not Page.IsPostBackThen
ListLoad()
End If
End Sub
Private Sub ListLoad()
Dim di As New DirectoryInfo("C:")
With lstFiles
.DataSource = di.GetFiles("*.*")
.DataTextField = "Name"
.DataBind()
End With
End Sub
FIGURE8: Displaying thelist of files.
Althoughit s peripheral to the discussion, it s interesting to note that you canretrieve an array of objects FileInfoobjects, in this example and bind them to a ListBox control. By setting the DataTextField property to Name,the page framework retrieves the Nameproperty of each FileInfo object anddisplays that value within the list box.
When youselect an item from the list box, the code in FIGURE 9 displays the output fromthe Format method within a tablecontaining four Label controls onthe page.
Private Sub lstFiles_SelectedIndexChanged( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles lstFiles.SelectedIndexChanged
Dim fa As FileAttributes= _
File.GetAttributes("C:" &lstFiles.SelectedItem.Text)
Dim typ As System.Type =GetType(FileAttributes)
lblFormatD.Text = System.Enum.Format(typ,fa, "d")
lblFormatG.Text = System.Enum.Format(typ,fa, "g")
lblFormatX.Text = System.Enum.Format(typ,fa, "x")
lblFormatF.Text = System.Enum.Format(typ,fa, "f")
End Sub
FIGURE9: Output from the Format method whenyou select an item from the list box.
Thiscode uses the shared GetAttributesmethod of the File class to retrievethe attributes of the file you ve selected. After creating a System.Type object representing theenumerated type, by using the GetTypefunction in VB .NET, the code calls the Enum.Formatmethod four times to show off each of the possible outputs.
Creating Enumerations
You cancreate your own enumerations, of course. In a class (or module, in VB .NET),you can add a declaration for an enumeration by using a construct like this:
Private Enum SeasonsEnumAs Integer
None
Winter
Spring
Summer
Autumn
All
End Enum
You canchoose the scope modifier you need, although this example uses the Private keyword to limit theenumeration to the current class. The type of the enumeration can be any of Byte, Short, Integer, or Long. If you don t supply values forthe items within the enumeration, the compiler assigns them sequential valuesstarting with 0. If you want to supply an item with an explicit value, you canadd the value like this (setting the value of None to 0 explicitly):
Private Enum SeasonsEnumAs Integer
None = 0
Winter
Spring
Summer
Autumn
End Enum
Onceyou ve set the value of any item within the enumeration, items following theitem you ve specified receive consecutive increasing integer values. (In thiscase, Winter would be1, Spring would be 2,and so on.) Setting Noneto 0 is the default behavior, but adding the explicit value never hurts, andyou might want to use a non-default value.
If youwant to create an enumeration in which values can be combined (like the FileAttributes enumeration you sawearlier), simply set the values of the items to be bit values 0, 1, andpowers of 2 such as 2, 4, 8, 16, and so on. In addition, you should add the Flags attribute to the enumeration, sothe enumeration looks like this:
_
Private Enum SeasonsEnum As Integer
None = 0
Winter = 1
Spring = 2
Summer = 4
Autumn = 8
End Enum
Althoughthe .NET run time doesn t distinguish between normal enumerations and bitmappedenumerations, specific languages may (VB .NET does not). Adding the attributemakes it clear, by reading the code, that your enumeration is intended to allowcombinations of values rather than a single, mutually exclusive value. Giventhe SeasonsEnum enumeration, youcould write code like this:
Dim CoolSeasons As SeasonsEnum = _
SeasonsEnum.Autumn Or SeasonsEnum.Spring
Inaddition, the Format methoddifferentiates between bitfield enumerations that use the Flags attribute and those that don t. Imagine you call the Format method like this:
Response.Write( _
System.Enum.Format(GetType(SeasonsEnum), 3,"G"))
Ifyou ve included the Flags attribute on the SeasonsEnum definition, you ll see Winter, Spring onthe page. Without the Flagsattribute, you ll simply see 3. (The F formatting specifierdoesn t make this distinction and displays Winter, Springno matter whether you ve included the Flagsattribute or not.)
Thefinal method provided by the Enumclass, Parse, allows you to providetext representing an item (or items) from the enumeration and have the .NETFramework convert the text into values within the enumeration. In other words,the Parse method converts from itemnames to item values (the opposite of the GetNamemethod). This shared method requires you to pass in a type and a string andreturns an enumerated value corresponding to the text you supplied. Theconversion is case-sensitive, however, so make sure you supply the textcorrectly. For example, you could call the Parsemethod like this:
Dim typ AsSystem.Type = GetType(SeasonsEnum)
Dim HotSeasonAs SeasonsEnum = _
System.Enum.Parse(typ, "Summer")
Inaddition, the Parse method canextract combinations of values from a comma-delimited list of item names. Forexample, the following code could replace the earlier example:
Dim typ AsSystem.Type = GetType(SeasonsEnum)
Dim CoolSeasonsAs SeasonsEnum = _
System.Enum.Parse(typ, "Autumn,Spring")
To testthe Parse method, you can browse toBitFieldEnums.aspx in the sample project and enter any combination of the itemsin the SeasonsEnum enumeration intothe text box named txtAttr at the bottom of the page. Click the button labeled Parse, and the page s code will attemptto parse the text you ve entered, by using this procedure:
' Parse theattributes listed in txtAttr.
Try
Dim typ As System.Type = GetType(SeasonsEnum)
lblResults.Text = "You entered: "& _
CStr(System.Enum.Parse(typ, txtAttr.Text))
Catch
lblResults.Text = String.Format( _
"Unable to parse '{0}'",txtAttr.Text)
End Try
If youenter a valid string, the code will display the corresponding numeric value. Ifnot, you ll see an error message. Note that this code uses the CStr function, rather than the ToString method. There s a differencebetween the two. CStr simplyconverts from the numeric value into a string representation (from 3 to "3", for example). The ToStringmethod (a method provided by the base Objectclass, and inherited and often overridden by every other class) converts thevalue back into text. If you had entered Summer, Winter,the CStr function would cause thevalue 5 to be displayed on the page. The ToString method would simply display Summer, Winter back at you. Of course, along theway, the code would have parsed your original entry into enumerated values andthen would have converted the values back into text. The success of thisconversion could convince you you d entered correct values, at least. But thepoint of this example was to convert from text to corresponding numeric values,and the ToString method won t dothat for you.
Asyou ve seen, the Enum class providescomplete programmatic support for working with enumerated values from withinyour applications. Although enumerationsare little more than named groups of literal, integral values, you can iteratethrough the items, look up values by name or by number, and bind controls tothe lists of values. Whether you re a VB .NET or C# developer, you ll find thatknowing the capabilities of the Enumclass will give you flexibility and power in taking advantage of these usefuldata structures.
Thefiles referenced in this article are available for download.
Ken Getz isa senior consultant with MCW Technologies and splits his time betweenprogramming, writing, and training. He specializes in tools and applicationswritten in Visual Studio .NET and Visual Basic .NET. Ken is co-author ofseveral books, including ASP.NET Developer s Jumpstart with Paul D. Sheriff, Access 2002 Developer s Handbook with Paul Litwin and Mike Gunderloy, Visual Basic Language Developer s Handbook with Mike Gilbert, and VBA Developer s Handbook with Mike Gilbert. Ken co-wrote the training materials forAppDev s VB .NET, ASP.NET, Access 97 and 2000, Visual Basic 5.0, and VisualBasic 6.0 classes. He frequently speaks at technical conferences and is acontributing editor for Microsoft Office Solutions magazine.
Tell us what you think! Please send any comments about thisarticle to [email protected] include the article title and author.
About the Author
You May Also Like