Defining Descriptive Text for Enumeration MembersBy Scott Mitchell
An enumeration is a special type in the .NET Framework that is comprised of a number of named constants. While you might not have created an enumeration type yourself, you have likely used enumerations many times in day-to-day programming. For example, the rows in a GridView have a
RowTypeproperty that returns an enumeration of type
DataControlRowTypethat indicates the row's type:
DataRow, and so on.
When working with an enumeration we may need to display a descriptive message based on the enumeration's value. For example, using ASP.NET's
Membership system you can programmatically create a new user account calling the
CreateUser method. This method specifies the success or failure of the
operation via the
This enumeration has members like
DuplicateUserName, and the like. When
calling this method from an ASP.NET page you might want to show the user a descriptive message based on this enumeration value.
This article explores three different ways to provide descriptive text for enumeration members. Read on to learn more!
A First Stab At Displaying Descriptive Text Based On An Enumeration Value
You're sitting at your desk, feverishly pounding out code trying to hit a near impossible deadline. Your building a website that needs to support user accounts and are in the middle of creating the registration page. Rather than use the CreateUserWizard Web control, you have a custom user interface and are calling the
Membership.CreateUsermethod in the page's code-behind class to create the new user account. You've got your user interface done and you've written the code to call
Membership.CreateUserand to redirect the user to a subsequent page should when their account was created successfully. All that remains is to add some feedback to the user if their account was not created successfully.
Your code to call the
Membership.CreateUser method looks something like this:
Note that a variable of type
MembershipCreateStatus is created before the call to the
Membership.CreateUser. This variable is then passed into
Membership.CreateUser method as an
out parameter (or as a
ByRef parameter, in VB parlance). In a nutshell, the
Membership.CreateUser method assigns a value to this variable based on what happened when attempting to create the user account.
Your job is to display a message based on the value of
createStatus after the call to
The simplest approach and the one you might take given your time constraints is to simply add a
switch statement or a series of
See Joe Stagner's blog entry Code
Snippet: Manually Creating a New ASP.NET Membership User in C# for a more thorough example of displaying a descriptive message based on the value of the
MembershipCreateStatus enumeration returned by the
This approach certainly gets the job done, but has a couple of drawbacks. First, it embeds the business rules - the association of the descriptive text with the
enumeration values - in the presentation layer. More importantly, it tightly couples this logic with this web page. What happens if you need to also add a registration
option to the admin pages that allows for an administrator to register a new user? You'd have to copy and paste these
which means if the verbage needs to change at a future date you've got two places that need to be updated.
A better approach is to put the descriptive text for each entry somewhere else. This article explores how to move this textual information to three different places: into an extension method; into a resource file; and into the enumeration definition.
Switch Statement /
Else Statements Into An Extension Method
Extension methods are a useful way for a developer to add methods to an existing type. Typically, extension methods are used to add functionality to classes in the .NET Framework, but they can also be used to add methods to enumerations, whether those enumerations exist as part of the .NET Framework or were created by you. For an in-depth look at extension methods be sure to read Extending Base Type Functionality with Extension Methods.
With extension methods we can add a method to an enumeration type - named, say,
ToDescriptiveString() - that contains the
else statements used to determine the text to emit based on value. The following code creates such an extension method:
With this code in place, the ASP.NET page that calls the
Membership.CreateUser method has been greatly simplified, as we can now emit the status using
one line of code, as the snippet below shows. First, the
Membership.CreateUser method is called to create the user account. If the user account was created
successfully, the user is redirected to
UserCreated.aspx. If, however, the account was not successfully created the failure reason is displayed in a Label
lblCreationError). The text explaining the reason for failure is returned by the
ToDescriptiveString() extension method.
Putting the logic that determines the descriptive text based on the selected enumeration value into the
ToDescriptiveString() extension method keeps the
clutter out of the ASP.NET page, making it more terse and more readable. More importantly, the extension method serves as a single location for this logic, meaning that
if we need to display a descriptive message based on the value of the
MembershipCreateStatus enumeration elsewhere in our codebase, we don't have to rewrite
that code or copy and paste. Instead, we just call the same extension method.
Pulling Enumeration Descriptions From A Resource File
Rather than hard-coding the descriptive text in the extension method you may want to move the text associated with each enumeration value to a separate store. This is especially useful if the text for each status can vary based on some external condition. For example, if you are building a multilingual website then the text associated with each enumeration status would vary based on the language of the user visiting the site. The various translations of an enumeration's descriptive text can be stored in a resource files.
The demo available for download at the end of this article includes a demo using resource files (
ByResource.aspx). This page has a TextBox where the visitor
can enter a directory on the web server's file system. A GridView control beneath the TextBox lists the files in the selected directory along with their file size (in bytes)
and file attributes. The list of files in the specified directory is retrieved using the
GetFiles method, which returns an array of
FileInfo objects. The
FileInfo class has a property named
Attributes which is an enumeration of type
This enumeration indicates the attributes on the file - whether it's archived, a hidden file, read-only, and so on. (Bear in mind that multiple attributes can apply
to a single file. For more information on how enumerations can be used to specify multiple values and for code examples that show how to determine which, of the possible
values, are indeed selected, refer to Understanding Enumerations.)
In addition to the TextBox and GridView, there's also a DropDownList on the page from which the user can select his preferred language - English or French. Based on
the selection, the thread processing the request has its
CurrentCulture property assigned to the appropriate culture string - "en-US" for English and
"fr-FR" for French.
There is a
ToDescriptiveStringUsingResourceFile() extension method defined for the
FileAttributes enumeration that is similar to the
ToDescriptiveString() extension method for the
MembershipCreateStatus enumeration that we examined earlier. However, instead of hard-coding
the descriptive text, the
ToDescriptiveStringUsingResourceFile() extension method calls the
GetGlobalResourceObject method to retrieve
the descriptive text from a resource file. There are two resource files defined in the
FileAttributeDescriptions.resx- contains the descriptive text entries for the
FileAttributesenumeration for the default culture ("en-US").
FileAttributeDescriptions.fr.resx- contains the descriptive text entries for the
FileAttributesenumeration for the French culture ("fr").
FileAttributeDescriptions.resxfile there are entries like:
Archive- The file is archived.
Compressed- The file is compressed.
Normal- This file has no attributes set.
FileAttributeDescriptions.resxfile these entries are en français:
Archive- Ce dossier est archivé.
Compressed- Ce dossier est serré.
Normal- Ce dossier n'a pas de série d'attribut.
ToDescriptiveStringUsingResourceFile()extension method. Because the
FileAttributesenumeration can specify multiple values, a list of strings (
descriptions) is maintained, adding the descriptive text to the list for each matching enumeration value. The string returned by the
ToDescriptiveStringUsingResourceFile()method is the combination of these individual descriptions, each separated by a
<br />tag. Also take note of the code used to retrieve a value from the resource file. The
GetGlobalResourceObjectmethod is passed the name of the global resource file, the name of the string to retrieve, and the culture of the thread processing the request. The
GetGlobalResourceObjectmethod uses this information to retrieve the appropriate block of text from the appropriate resource file.
The screen shot below shows the
ByResource.aspx page when viewing the files of the
C:\Windows directory with English as the preferred language.
Here is the same page after selecting the French option from the drop-down list. Note that the file attribute text now uses the French translation.
Using Attributes To Define Descriptive Text Within the Enumeration Itself
So far we have examined two techniques for storing descriptive text for an enumerations members - in an extension method and in resource files. You can alternatively store an enumeration's descriptions directly in the enumeration definition itself, as attributes. (This option only works for enumerations you create and not for existing enumerations in the .NET Framework.) When defining an enumeration you can use the
DescriptionAttributeclass, which is found in the
System.ComponentModelnamespace. To use this attribute, be sure to add a
using System.ComponentModelstatement to the file where the enumeration is defined, and then you can use the
DescriptionAttributeclass like so:
DescriptionAttribute class allows us to supply descriptive text for each enumeration member directly in the enumeration itself. We can then read these
attribute values programmatically using reflection. The following extension method comes from Brenton House's blog entry
Extension Methods with Enum Description:
First things first - note that this extension method is applied to the
Enum type, which is the type that all enumerations extend. That means you'll have
this extension method at your disposal for any enumeration. The
ToDescriptiveTextUsingAttributes() method starts by converting the enumeration value
into a string. If the enumeration value does not support multiple values being selected (or has only one value selected) then the
ToString() method returns
the name of the selected member. (The member names in the
OldComputers enumeration are
If the enumeration supports multiple values and has more than one value selected,
ToString() returns the names of the selected members separated by a comma.
Next, a new string array is created (
description) to hold the descriptive text for the selected enumeration member(s). (The descriptive texts in the
OldComputers enumeration are: "Packard Bell Legend IV"; "Commodore SX-64"; and "Tandy 1000 HX".) The selected member(s) are then enumerated
for loop and the
GetCustomAttributes methods are used to first get information about the enumeration member
and then about its
Description attribute. If there was a
Description attribute for the selected member then it is used as the descriptive text;
otherwise, the name of the member is used. After the selected member(s) are enumerated, they are returned as a string, with each member separated by a comma.
The demo available for download includes a page that illustrates using the
ToDescriptiveTextUsingAttributes() method to populate a DropDownList control
with the options from an enumeration, using the descriptive text as the text of the DropDownList and the enumeration member name as the value. The following code
ListItem objects for the three members in the
OldComputers enumeration and then adds them to the DropDownList's
The above code results in a DropDownList with the following display:
When working with enumerations there are times when it's useful to associate a human-friendly, descriptive text with each enumeration value. As we saw in this article, this can be accomplished in a number of ways. The text can be hard-coded within an extension method. It can be embedded in resource files, which is a great option for multilingual sites. Or it can be defined as part of the enumeration itself, using attributes. Each choice has some pros and cons, but all three are better options than writing
elsestatements in your presentation layer to display descriptive text based on an enumeration value.