Enum with a human face

A problem

Quite often we have to use enums for a limited set of values. They are very easy to use in your code, but there are problems for bringing them to the interface of the application. Not only in Russian but in English. The values ​​in enum may consist of several words logically and embarrassing them to show in the user interface. For example:

public enum MyEnum {
    None,
    CompositeValue,
    Single
}

Naturally, it is show to the customer CompositeValue is not good. Much better to show “Composite Value”. Or, to translate it into Russian.

How it was

Now in the code you can find the following monstrous construction:

private const string LogSeverity_All = "Все";
private const string LogSeverity_Off = "Никакие";
private const string LogSeverity_Critical= "Критические";
private const string LogSeverity_Error = "Ошибки";
private const string LogSeverity_Warning = "Предупреждения";
private const string LogSeverity_Information = "Информационные";
private const string LogSeverity_Verbose = "Расширенные";
private const string LogSeverity_ActivityTracing = "Трассировочные";

To translate the text into an enumerated type using a separate code, where each potential case may be a mistake and should be tested.

private static FileSeverityFilter StringToFileSeverityFilter(string value)  {
    switch (value) {
       case LogSeverity_All:
          return FileSeverityFilter.All;
       case LogSeverity_Critical:
          return FileSeverityFilter.Critical;
       case LogSeverity_Error:
          return FileSeverityFilter.Error;
       case LogSeverity_Warning:
          return FileSeverityFilter.Warning;
       case LogSeverity_Information:
          return FileSeverityFilter.Information;
       case LogSeverity_Verbose:
          return FileSeverityFilter.Verbose;
       case LogSeverity_ActivityTracing:
          return FileSeverityFilter.ActivityTracing;
       default:
          return FileSeverityFilter.Off;
     }
}

And there is an enumerated type

enum FileSeverityFilter  {
    All = 0,
    Off,
    Critical,
    Error,
    Warning,
    Information,
    Verbose,
    ActivityTracing
}

And to generate values ​​for display property is used

public List<string> LogSeverities {
    get {
        return new List<string> {
                LogSeverity_All,
                LogSeverity_Off,
                LogSeverity_Critical,
                LogSeverity_Error,
                LogSeverity_Warning,
                LogSeverity_Information,
                LogSeverity_Verbose,
                LogSeverity_ActivityTracing
               };

     }
}

Where again it is easy to forget to specify the new type.
Total:

  • A lot of code where it’s easy to make mistakes, and make out all of this will be hard enough.
  • No obvious connection type values ​​and the signatures of men.
  • Conversion should be done for each enumeration type.

Became

You can go the other way, getting rid of all the shortcomings, leaving only one where the error occurred, for all possible enumerations. FOr it we will deploy the attribute is Description.

public enum MyEnum {
    [Description("Не выбрано")]
    None,

    [Description("Составное значение")]
    CompositeValue,

    [Description("Значение")]
    Single
}

Immediately we see a description of what type of matches.

To get the value from the description, you should use the following code:

var type = typeof (MyEnum);
var fieldInfo = type.GetField(enumerate.ToString());
var attributes = (DescriptionAttribute[]) fieldInfo.GetCustomAttributes(typeof (DescriptionAttribute), false);
var result = (attributes.Length > 0) ? attributes[0].Description : enumerate.ToString();

Since it is inconvenient to write every time you select a class of extensions.

public static class EnumExtenders {
    public static string ToStringX(this Enum enumerate) {
        var type = enumerate.GetType();
        var fieldInfo = type.GetField(enumerate.ToString());
        var attributes = (DescriptionAttribute[]) fieldInfo.GetCustomAttributes(typeof (DescriptionAttribute), false);
        return (attributes.Length > 0) ? attributes[0].Description : enumerate.ToString();
    }
}

Now we can write

MyEnum.CompositeValue.ToStringX () // will compound the value

Already much easier and can be used for any enum.

For a list of values​​, the code is not very complicated.

public static List<string> Descriptions(this Enum enumerate) {
     var values = Enum.GetValues(enumerate.GetType());
     var descriptions = new List<string>(values.Length);

     foreach (var enumVal in values) {
          descriptions.Add(((Enum) enumVal).ToStringX());
     }

     return descriptions;
}

Uses:

var descriptions = MyEnum.Single.Descriptions();

The only disadvantage that the use by any enumeration value.

Don’t you want to write this method?

var actual = Enum.GetValues(typeof(MyEnum))
     .Cast<MyEnum>()
     .Select(i => i.ToStringX());

Use directly in your production code.

A result

In my opinion submitted by the way is more compact and versatile. In addition, the test should be only one place, everything is compact.

  • Do not be afraid of tipping over on the values ​​of the user interface, since all comes.
  • Visibility of use.
  • The code size is reduced at times

Source code

Hard’n’heavy

Tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>