Defining Descriptive Text for Enumeration Members
By Scott Mitchell
Introduction
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
RowType
property that returns an
enumeration of type DataControlRowType
that
indicates the row's type: Header
, Footer
, 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 Membership
class's CreateUser
method. This method specifies the success or failure of the
operation via the MembershipCreateStatus
enumeration.
This enumeration has members like Success
, InvalidUserName
, InvalidPassword
, 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.CreateUser
method 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.CreateUser
and 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:
MembershipCreateStatus createStatus;
|
Note that a variable of type MembershipCreateStatus
is created before the call to the Membership.CreateUser
. This variable is then passed into
the 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 Membership.CreateUser
.
The simplest approach and the one you might take given your time constraints is to simply add a switch
statement or a series of if
... else
like so:
if (createStatus == MembershipCreateStatus.InvalidUserName)
|
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 Membership.CreateUser
method...
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 if
... else
statements,
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.
Moving the Switch
Statement / If
... 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 switch
statement
or if
... else
statements used to determine the text to emit based on value. The following code creates such an extension method:
public static class MembershipCreateStatusExtensions
|
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
control (lblCreationError
). The text explaining the reason for failure is returned by the ToDescriptiveString()
extension method.
MembershipCreateStatus createStatus;
|
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 DirectoryInfo
class's GetFiles
method, which returns an array of
FileInfo
objects. The FileInfo
class has a property named
Attributes
which is an enumeration of type FileAttributes
.
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 App_GlobalResources
folder:
FileAttributeDescriptions.resx
- contains the descriptive text entries for theFileAttributes
enumeration for the default culture ("en-US").FileAttributeDescriptions.fr.resx
- contains the descriptive text entries for theFileAttributes
enumeration for the French culture ("fr").
FileAttributeDescriptions.resx
file there are entries like:
Archive
- The file is archived.Compressed
- The file is compressed.Normal
- This file has no attributes set.
FileAttributeDescriptions.resx
file 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 FileAttributes
enumeration 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 GetGlobalResourceObject
method 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 GetGlobalResourceObject
method uses this information
to retrieve the appropriate block of text from the appropriate resource file.
public static class FileAttributesExtensions
|
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
DescriptionAttribute
class, which is found in the System.ComponentModel
namespace. To use this attribute, be sure to add a using System.ComponentModel
statement
to the file where the enumeration is defined, and then you can use the DescriptionAttribute
class like so:
using System.ComponentModel;
|
The 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:
public static class EnumAttributes
|
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 PackardBell
, Commodore
, and Tandy
.)
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
via a for
loop and the GetField
and 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
creates three ListItem
objects for the three members in the OldComputers
enumeration and then adds them to the DropDownList's Items
collection:
var items = new ListItem[3]
|
The above code results in a DropDownList with the following display:

Conclusion
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
if
... else
statements in your presentation layer to display descriptive text based on an enumeration value.
Happy Programming!
Attachments:
Further Readings: