-2

I often come across situation where I have an enum that needs to be parsed from a user friendly/description string. Later on, that same enum needs to be converted to user friendly string. I'm trying to come up with a way to generalize this code, so that I can easily add new enum definitions, without having to repeat conversion code. This is what I've come up so far, but I still don't like it. I still have two lines of code (IdToName and NameToId calls) that I need to repeat in each derived class. Is there a way I can modify this, so there is no more repetition in derived classes (all conversion functions are defined in base class only):

Here's my base class:

public class DictionaryEnum
{
    public static T NameToId<T>(Dictionary<T, string> idToNames, string name, T defaultValue)
    {
        foreach (var idToName in idToNames)
        {
            if (string.Compare(idToName.Value, name, StringComparison.CurrentCultureIgnoreCase) == 0)
                return idToName.Key;
        }

        return defaultValue;
    }

    public static string IdToName<T>(Dictionary<T, string> idToNames, T id, T defaultValue)
    {
        if (!idToNames.ContainsKey(id))
            id = defaultValue;

        return idToNames[id];
    }
}

Here's a first enum example:

public class AttachmentType : DictionaryEnum
{
    public enum Id
    {
        Undefined = 1,
        CameraImage = 2,
        AlbumImage = 3,
        Video = 4,
        Audio = 5,
    }

    private static readonly Dictionary<Id, string> _idToNames = new Dictionary<Id, string>
    {
        { Id.Undefined, "N/A" },
        { Id.CameraImage, "Camera Image" },
        { Id.AlbumImage, "Album Image" },
        { Id.Video, "Video" },
        { Id.Audio, "Audio" },
    };

    public static Id NameToId(string name) => NameToId(_idToNames, name, Id.Undefined);
    public static string IdToName(Id id) => IdToName(_idToNames, id, Id.Undefined);
}

And here's a second enum example:

public class TestStatus : DictionaryEnum
{
    public enum Id
    {
        Undefined = 0,
        Opened = 1,
        Started = 2,
        Closed = 3,
    };

    private static readonly Dictionary<Id, string> _idToNames = new Dictionary<Id, string>
    {
        { Id.Undefined, "is_undefined" },
        { Id.Opened, "is_opened" },
        { Id.Started, "is_started" },
        { Id.Closed, "is_closed" },
    };

    public static Id NameToId(string name) => NameToId(_idToNames, name, Id.Undefined);
    public static string IdToName(Id id) => IdToName(_idToNames, id, Id.Undefined);
}
Eternal21
  • 4,190
  • 2
  • 48
  • 63
  • This is what you want: https://stackoverflow.com/a/40995755/4716488 You can define an extension method to `Enum` which uses reflection to grab the friendly `Display.Name` annotation of each enum member. – ethane Apr 21 '18 at 18:58
  • Possible duplicate of [How to display the name of enum display attribute](https://stackoverflow.com/questions/40995593/how-to-display-the-name-of-enum-display-attribute) – ethane Apr 21 '18 at 18:58

1 Answers1

0

All that feels too noisy...

I faced a similar demand some years ago and used the following solution. Decorate your enums with a DescriptionAttribute and put the descriptive text in there. like this:

public enum Id
{
    [Description("Undefined")]
    Undefined = 1,

    [Description("Camera Image")]
    CameraImage = 2,

    [Description("Album Image")]
    AlbumImage = 3,

    [Description("Video Image")]
    Video = 4,

    [Description("Audio")]
    Audio = 5,
}

Next, implement an extension method that accepts enums and retrieve the custome Description attribute.

public static class EnumExtensions
{
    public static string GetDescription<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible // Enums do implement IConvertible
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new ArgumentException("TEnum is not an enum type :(");
        }

        var et = typeof(TEnum);
        var name = Enum.GetName(et, value);

        result = et.GetField(name)
            ?.GetCustomAttributes(false)
            ?.OfType<DescriptionAttribute>()
            ?.FirstOrDefault()
            .Description
        ;

        return result;
    }
}

Enjoy.

Bozhidar Stoyneff
  • 3,576
  • 1
  • 18
  • 28