Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have userfriendly names for enumerations? [duplicate]

Tags:

I have an enumeration like

Enum Complexity {   NotSoComplex,   LittleComplex,   Complex,   VeryComplex } 

And I want to use it in a dropdown list, but don't want to see such Camel names in list (looks really odd for users). Instead I would like to have in normal wording, like Not so complex Little complex (etc)

Also, my application is multi-lang and I would like to be able to display those strings localized, and I use a helper, TranslationHelper(string strID) which gives me the localized version for a string id.

I have a working solution, but not very elegant: I create a helper class for the enum, with one member Complexity and ToString() overwritten, like below (code simplified)

public class ComplexityHelper {     public ComplexityHelper(Complexity c, string desc)     { m_complex = c; m_desc=desc; }      public Complexity Complexity { get { ... } set {...} }     public override ToString() { return m_desc; }      //Then a static field like this       private static List<Complexity> m_cxList = null;      // and method that returns the status lists to bind to DataSource of lists     public static List<ComplexityHelper> GetComplexities()      {         if (m_cxList == null)         {            string[] list = TranslationHelper.GetTranslation("item_Complexities").Split(',');            Array listVal = Enum.GetValues(typeof(Complexities));            if (list.Length != listVal.Length)                throw new Exception("Invalid Complexities translations (item_Complexities)");            m_cxList = new List<Complexity>();            for (int i = 0; i < list.Length; i++)            {              Complexity cx = (ComplexitylistVal.GetValue(i);              ComplexityHelper ch = new ComplexityHelper(cx, list[i]);              m_cxList.Add(ch);            }         }         return m_cxList;     } } 

While workable, I'm not happy with it, since I have to code it similarily for various enums I need to use in picklists.

Does anyone have a suggestion for a simpler or more generic solution?

Thanks Bogdan

like image 290
bzamfir Avatar asked Aug 25 '09 22:08

bzamfir


People also ask

Can two enum names have the same value?

1. Two enum names can have same value. For example, in the following C program both 'Failed' and 'Freezed' have same value 0.

Can enums have names?

The attributes Color. RED , Color. GREEN , etc., are enumeration members (or enum members) and are functionally constants. The enum members have names and values (the name of Color.

How do I override strings in enum?

ToString() and only provide switch case statements for the enum values that you want to override. In your example, I get that they're all different but in actual use cases, I suspect that most of the single-word enum values will suffice and you'll only be providing overrides for multi-word enum values.


1 Answers

Basic Friendly names

Use the Description attribute:*

enum MyEnum {     [Description("This is black")]     Black,     [Description("This is white")]     White } 

And a handy extension method for enums:

public static string GetDescription(this Enum value) {     FieldInfo field = value.GetType().GetField(value.ToString());     object[] attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true);     if(attribs.Length > 0)     {         return ((DescriptionAttribute)attribs[0]).Description;     }     return string.Empty; } 

Used like so:

MyEnum val = MyEnum.Black; Console.WriteLine(val.GetDescription()); //writes "This is black" 

(Note this doesn't exactly work for bit flags...)

For localization

There is a well-established pattern in .NET for handling multiple languages per string value - use a resource file, and expand the extension method to read from the resource file:

public static string GetDescription(this Enum value) {     FieldInfo field = value.GetType().GetField(value.ToString());     object[] attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true));     if(attribs.Length > 0)     {         string message = ((DescriptionAttribute)attribs[0]).Description;         return resourceMgr.GetString(message, CultureInfo.CurrentCulture);     }     return string.Empty; } 

Any time we can leverage existing BCL functionality to achieve what we want, that's definitely the first route to explore. This minimizes complexity and uses patterns already familiar to many other developers.

Putting it all together

To get this to bind to a DropDownList, we probably want to track the real enum values in our control and limit the translated, friendly name to visual sugar. We can do so by using an anonymous type and the DataField properties on the list:

<asp:DropDownList ID="myDDL"                   DataTextField="Description"                   DataValueField="Value" />  myDDL.DataSource = Enum.GetValues(typeof(MyEnum)).OfType<MyEnum>().Select(     val => new { Description = val.GetDescription(), Value = val.ToString() });  myDDL.DataBind(); 

Let's break down that DataSource line:

  • First we call Enum.GetValues(typeof(MyEnum)), which gets us a loosely-typed Array of the values
  • Next we call OfType<MyEnum>() which converts the array to an IEnumerable<MyEnum>
  • Then we call Select() and provide a lambda that projects a new object with two fields, Description and Value.

The DataTextField and DataValueField properties are evaluated reflectively at databind-time, so they will search for fields on DataItem with matching names.

-Note in the main article, the author wrote their own DescriptionAttribute class which is unnecessary, as one already exists in .NET's standard libraries.-

like image 177
Rex M Avatar answered Sep 25 '22 15:09

Rex M