Click here to Skip to main content
15,867,835 members
Articles / Programming Languages / C#
Article

Descriptive Enumerations

Rate me:
Please Sign up or sign in to vote.
4.87/5 (28 votes)
8 Mar 20063 min read 84.4K   724   50   25
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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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".

C#
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:

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

Additionally, our base class defines some other useful methods:

C#
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:

C#
SeatType.GetEnumFromCode(seatkind);

like we did above. You can actually just do:

C#
SeatType c = (SeatType) GetSeatTypeFromDatabaseSomeWhere();

Likewise, you can call:

C#
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


Written By
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 Pin
S.P.Tiwari7-Dec-11 18:13
professionalS.P.Tiwari7-Dec-11 18:13 
GeneralBuild warning Pin
golan.barnov10-Sep-07 3:23
golan.barnov10-Sep-07 3:23 
Generalswitch Pin
DynV15-Jun-07 4:53
DynV15-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 Pin
Jason Law16-Apr-07 17:55
Jason Law16-Apr-07 17:55 
AnswerRe: string Data Type for CodeType Pin
Tim Clark17-Apr-07 3:56
Tim Clark17-Apr-07 3:56 
QuestionWorks Great But .... What About Switch Statements? Pin
S432**%$13-Oct-06 12:31
S432**%$13-Oct-06 12:31 
AnswerRe: Works Great But .... What About Switch Statements? Pin
Tim Clark16-Oct-06 5:37
Tim Clark16-Oct-06 5:37 
QuestionWhere is DescriptiveEnumInvalidCodeException Pin
okcode23-Jul-06 23:19
okcode23-Jul-06 23:19 
GeneralXmlSerializable Pin
ryanmunson10-May-06 11:59
ryanmunson10-May-06 11:59 
GeneralRe: XmlSerializable Pin
Tim Clark11-May-06 4:51
Tim Clark11-May-06 4:51 
GeneralRe: XmlSerializable Pin
ryanmunson11-May-06 15:54
ryanmunson11-May-06 15:54 
GeneralRe: XmlSerializable Pin
Tim Clark11-May-06 17:01
Tim Clark11-May-06 17:01 
GeneralRe: XmlSerializable Pin
ryanmunson11-May-06 17:58
ryanmunson11-May-06 17:58 
Generalswitch Pin
roman.wagner29-Mar-06 6:15
roman.wagner29-Mar-06 6:15 
GeneralRe: switch Pin
Tim Clark30-Mar-06 9:36
Tim Clark30-Mar-06 9:36 
QuestionVery Nice indeed, but...increments? Pin
Tim Speekenbrink24-Mar-06 5:03
Tim Speekenbrink24-Mar-06 5:03 
AnswerRe: Very Nice indeed, but...increments? Pin
Tim Clark24-Mar-06 5:22
Tim Clark24-Mar-06 5:22 
GeneralRe: Very Nice indeed, but...increments? Pin
Tim Speekenbrink24-Mar-06 5:33
Tim Speekenbrink24-Mar-06 5:33 
QuestionNice, but what about [Flags] Pin
Memeoid15-Mar-06 7:54
Memeoid15-Mar-06 7:54 
AnswerRe: Nice, but what about [Flags] Pin
Tim Clark16-Mar-06 19:55
Tim Clark16-Mar-06 19:55 
JokeWonderfull Pin
Mohammad Mir mostafa15-Mar-06 2:39
Mohammad Mir mostafa15-Mar-06 2:39 
GeneralSmooth Pin
lofty_29-Mar-06 14:09
lofty_29-Mar-06 14:09 
GeneralAwesome Pin
Steve Hansen8-Mar-06 21:47
Steve Hansen8-Mar-06 21:47 
GeneralVery Nice! Pin
K.Collins8-Mar-06 3:58
K.Collins8-Mar-06 3:58 
Generalnice solution Pin
Ajek6-Mar-06 20:47
Ajek6-Mar-06 20:47 

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

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