Click here to Skip to main content
Click here to Skip to main content
Go to top

Descriptive Enumerations

, 8 Mar 2006
Rate this:
Please Sign up or sign in to vote.
Using .NET 2.0 generics to allow for enum like classes with human readable descriptions.

Introduction

Those of us who write ASP.NET for living often come across the problem of wanting to use enums in our pages. For example, you may have a page that allows someone to register for an airplane seat. Then, you may have some code that looks like:

public enum SeatType
{
    Window=1,
    Aisle=2
}

public class Registration
{
    ...
    SeatType wantsSeat;
    ...
}

Back in your ASP.NET page, you may loop over all the enum values, using something like:

    foreach (string s in Enum.GetNames(typeof(SeatType)))
    {
        string name = s;
        SeatType t = (SeatType) Enum.Parse(typeof(SeatType),s);
        int val = (int) t;
        
        //do something with name and val like 
        //add them to an <option> tag
    }

This code is a bit ugly, but it's worth keeping due to the fact that we can have methods like:

    public SeatType GetPassengerSeatType(Passenger p) {
        return p.Seat;
    }

The real issue arises when we add a new seat type to our enum that isn't a valid identifier. Note that Enum.GetNames simply returns the names of the enumerated constants. C# doesn't allow us to have something like:

public enum SeatType
{
    Window=1,
    Aisle=2,
    Anything Except Seat Near Bathroom
}

Since "Anything Except Seat Near Bathroom" isn't a valid identifier, I've seen several people make use of attributes to do something like this:

    public enum SeatType
    {    
        [Description("Window")] Window=1,
        [Description("Aisle")] Aisle=2,
        [Description("Anything Except Seat" + 
            " Near Bathroom")] AnythingExceptSeatNearBathroom
    }

    public static string GetEnumDescription(Enum value)
    {
        FieldInfo fi= value.GetType().GetField(value.ToString()); 
        DescriptionAttribute[] attributes = 
          (DescriptionAttribute[])fi.GetCustomAttributes(
          typeof(DescriptionAttribute), false);
        return (attributes.Length>0) ? 
                attributes[0].Description : 
                value.ToString();
    }

This code works, but it's not really good object oriented design: we're asking another class to retrieve information about our enum type. Clearly, what we would like to do is have a Description as a property of each member of our enum, rather than as an attribute of each member.

With .NET 2.0 and generics, we are able to have a very clean solution to the problem.

Using the code

I created a simple generic abstract class called DescriptiveEnum that will allow you to have...descriptive enums!

Before explaining how the DescriptiveEnum class works that makes this possible, I'll show you how to use it to solve the example we mentioned above. Here is the new SeatType "enum".

public class SeatType : DescriptiveEnum<SeatType,int>
{
    public static readonly SeatType Window = 
           new SeatType("Window Seat",1);
    public static readonly SeatType Aisle = 
           new SeatType("Aisle Seat", 2);
    public static readonly SeatType 
           AnythingExceptSeatNearBathroom = 
           new SeatType("Anything Except Seat Near Bathroom", 3);

    private SeatType(string desc, int code) : base(desc,code)
    {
        
    }
}

Only three things are necessary here:

  1. You need to inherit from DescriptiveEnum and pass the name of your inheriting class as the first generic type. The second generic type can be any value type that you want to use to store your enum values. By default, real .NET enums use integers to store constant enum values. So, I am doing the same thing in the example above. But again, you can store doubles, etc.
  2. Define a private constructor for your type that takes a string and the same type that you specified for the generic enum value. Since I specified int, I need to specify int in the constructor. You can't actually get this wrong; if you try to have a constructor that takes a double when you specified an int in your generic type, the compiler will throw an error at you. The important point to realize here is that the constructor should be private. Other classes should not be creating new instances of your enum type.
  3. Define public static readonly types of your class, and instantiate them by calling your private constructor, passing in a unique code for each enum. In the example above, I specified 1,2,3. You can make these anything you want as long as they are unique. If they are not unique, the class will throw an exception at run time.

So after doing the above, we have a data type that looks and feels just like a built-in enum, but with our descriptions:

SeatType c = SeatType.Aisle;
string desc = SeatType.AnythingExceptSeatNearBathroom.Description;

Additionally, our base class defines some other useful methods:

SeatType c;
int seatkind = GetSeatTypeFromDatabaseSomeWhere();

c = SeatType.GetEnumFromCode(seatkind);

SeatType[] allSeatTypes = SeatType.GetEnumMembers();

Finally, with generics, the base class is able to define public static explicit operator conversions to and from the enum constant you define (int, in our example above). So, this lets you use casting exactly like you do with enums. So you don't even have to call:

SeatType.GetEnumFromCode(seatkind);

like we did above. You can actually just do:

SeatType c = (SeatType) GetSeatTypeFromDatabaseSomeWhere();

Likewise, you can call:

int x = (int) SeatType.Aisle

if you want. Although, generally, I would call the SeatType.Aisle.Code member.

And that's all there is to it. Generics is a beautiful thing.

History

  • 1.0 - original release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Tim Clark
Web Developer
United States United States
Tim Clark graduated in 2005 with an MS in Computer Science. He is currently employed as a .NET developer.

Comments and Discussions

 
GeneralMy vote of 4 PinmemberS.P. Tiwari7-Dec-11 18:13 
GeneralBuild warning Pinmembergolan.barnov10-Sep-07 3:23 
Generalswitch PinmemberDynV15-Jun-07 4:53 
switch works, just look at that code : http://www.java2s.com/Tutorial/CSharp/0040__Data-Type/Passenumtofunction.htm
 
I had a syntax problem using the column before the enum but I should've used it AFTER it.
Questionstring Data Type for CodeType PinmemberJason Law16-Apr-07 17:55 
AnswerRe: string Data Type for CodeType PinmemberTim Clark17-Apr-07 3:56 
QuestionWorks Great But .... What About Switch Statements? PinmemberS432**%$13-Oct-06 12:31 
AnswerRe: Works Great But .... What About Switch Statements? PinmemberTim Clark16-Oct-06 5:37 
QuestionWhere is DescriptiveEnumInvalidCodeException Pinmemberokcode23-Jul-06 23:19 
GeneralXmlSerializable Pinmemberryanmunson10-May-06 11:59 
GeneralRe: XmlSerializable PinmemberTim Clark11-May-06 4:51 
GeneralRe: XmlSerializable Pinmemberryanmunson11-May-06 15:54 
GeneralRe: XmlSerializable PinmemberTim Clark11-May-06 17:01 
GeneralRe: XmlSerializable Pinmemberryanmunson11-May-06 17:58 
Generalswitch Pinmemberroman.wagner29-Mar-06 6:15 
GeneralRe: switch PinmemberTim Clark30-Mar-06 9:36 
QuestionVery Nice indeed, but...increments? PinmemberTim Speekenbrink24-Mar-06 5:03 
AnswerRe: Very Nice indeed, but...increments? PinmemberTim Clark24-Mar-06 5:22 
GeneralRe: Very Nice indeed, but...increments? PinmemberTim Speekenbrink24-Mar-06 5:33 
QuestionNice, but what about [Flags] PinmemberMemeoid15-Mar-06 7:54 
AnswerRe: Nice, but what about [Flags] PinmemberTim Clark16-Mar-06 19:55 
JokeWonderfull Pinmembermohammad27200515-Mar-06 2:39 
GeneralSmooth Pinmemberlofty_29-Mar-06 14:09 
GeneralAwesome PinmemberXIUnin8-Mar-06 21:47 
GeneralVery Nice! PinmemberK.Collins8-Mar-06 3:58 
Generalnice solution PinmemberAjek6-Mar-06 20:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140922.1 | Last Updated 8 Mar 2006
Article Copyright 2006 by Tim Clark
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid