Click here to Skip to main content
15,891,745 members
Articles / Programming Languages / C#
Technical Blog

Adding descriptions, or other text, to enumeration values (supports localization!)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
14 Apr 2013CPOL2 min read 14.5K   5  
Adding descriptions, or other text, to enumeration values (supports localization!)

Description

Sometimes, when using enumerations, you need to express the value as something other than the string representation of the enumeration value itself. Let's say that I have the following enumeration that I want to put into a list for selection by a user:

C#
public enum MyEnum 
{
    LaptopComputer,
    TabletScreen,
    VRHeadSet
}

The list will contain the items as they are named in the enumeration, which ends up looking pretty silly, as these selections are obviously not plain English. As a solution to this problem, you could loop over the enumeration and create a switch statement, adding your own custom text to the list for each item in the enumeration, like so:

C#
foreach (var name in Enum.GetNames(typeof(MyEnum)))
{
    MyEnum myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), name);
    switch (myEnum)
    {
        case MyEnum.LaptopComputer:
            items.Add("Laptop Computer");
            break;
        case MyEnum.TabletScreen:
            items.Add("Tablet Screen");
            break;
        case MyEnum.VRHeadSet:
            items.Add("Virtual Reality Headset");
            break;
        default:
            break;
    }
}

Obviously that is not the best route to go, as you've not got your descriptions living in the loop that is populating your list, instead of living with the enumeration where they belong. The solution to this issue is simple... use the [Description] attribute that is available in the ComponentModel namespace in .NET to decorate your enumeration values.

C#
public​ enum MyEnum
{
    [Description("Laptop Computer")]
    LaptopComputer,
    [Description("Tablet Screen")]
    TabletScreen,
    // Note: We're passing in the resource key here, not the actual description.
    [LocalizedDescriptionAttribute("VRHeadSet")]
    VRHeadSet
}

Simple, right? Now we've got the descriptions where they belong- attached to the enumeration values themselves. (You'll notice the last enumeration value is a little different, which I will explain later.) So, now that we've got these descriptions attached to the values of our enumeration... how do we get at them from our code that is adding items to a list? Easy! We'll just create a method called GetDescription that takes an enum value, and returns the description via reflection.

C#
public static string GetDescription(MyEnum value)
{
    Type type = value.GetType();
    string name = Enum.GetName(type, value);
    if (name != null)
    {
        FieldInfo field = type.GetField(name);
        if (field != null)
        {
            DescriptionAttribute attr = Attribute.GetCustomAttribute(field, 
               typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (attr != null)
            {
                return attr.Description;
            }
        }
    }
    return null;
}

Now that we have a method to return the descriptions of the values, our loop can look something like this:

C#
foreach (var name in Enum.GetNames(typeof(MyEnum)))
{
    MyEnum myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), name);
    items.Add(EnumExtensions.GetDescription(myEnum));
}

That's much simpler than the first loop, right? Well, we can make it even more simple, and make the GetDescription method into an extension method, which you can then call right off of the end of a enumeration value. Making the method an extension method also means that it will apply to all of the enumerations in the namespace.

Now, let me explain the different attribute decoration on the VRHeadSet enumeration value. You've probably noticed that it is decorated with the LocalizedDescriptionAttribute, as opposed to the DescriptionAttribute. (This attribute inherits the previously described DescriptionAttribute.) This allows us to localize the descriptions on each of the enum values by overriding the string that is put into the underlying description attribute when it is created. The value that is put into the LocalizedDescriptionAttribute on the enumeration value is the name of the string resource in the application's resource file.

Code

C#
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Getting enum descriptions via extension method:");
        Console.WriteLine();
        Console.WriteLine("{0} has description '{1}'", MyEnum.Value1, MyEnum.Value1.GetDescription());
        Console.WriteLine("{0} has description '{1}'", MyEnum.Value2, MyEnum.Value2.GetDescription());
        Console.WriteLine("{0} has description '{1}'", MyEnum.Other, MyEnum.Other.GetDescription());
        Console.WriteLine();
        Console.WriteLine();
        Console.WriteLine("Getting enum descriptions via function call:");
        Console.WriteLine();
        Console.WriteLine("{0} has description '{1}'", MyEnum.Value1, EnumExtensions.GetDescription(MyEnum.Value1));
        Console.WriteLine("{0} has description '{1}'", MyEnum.Value2, EnumExtensions.GetDescription(MyEnum.Value2));
        Console.WriteLine("{0} has description '{1}'", MyEnum.Other, EnumExtensions.GetDescription(MyEnum.Other));
        Console.WriteLine();
        Console.WriteLine();
        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }
}
public enum MyEnum
{ 
    [Description("This is value 1")]
    Value1,
    [Description("This is value 2")]
    Value2,
    // Note: We're passing in the resource key here, not the actual description.
    [LocalizedDescriptionAttribute("OtherValueDescription")]
    Other,
}

public static class EnumExtensions
{
    public static string GetDescription(this Enum value)
    {
        Type type = value.GetType();
        string name = Enum.GetName(type, value);
        if (name != null)
        {
            FieldInfo field = type.GetField(name);
            if (field != null)
            {
                DescriptionAttribute attr = Attribute.GetCustomAttribute(field, 
                          typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attr != null)
                {
                    return attr.Description;
                }
            }
        }
        return null;
    }
}

public class LocalizedDescriptionAttribute : DescriptionAttribute
{
    public LocalizedDescriptionAttribute(string resourceId)
    : base(Resource.ResourceManager.GetString(resourceId))
    {
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
Check out my technical blog here: The Fyslexic Duck. You can find most of what I've put on CodeProject there, plus some additional technical articles.

Comments and Discussions

 
-- There are no messages in this forum --