Get Enum from Description attribute

228,948

Solution 1

public static class EnumEx
{
    public static T GetValueFromDescription<T>(string description) where T : Enum
    {
        foreach(var field in typeof(T).GetFields())
        {
            if (Attribute.GetCustomAttribute(field,
            typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
            {
                if (attribute.Description == description)
                    return (T)field.GetValue(null);
            }
            else
            {
                if (field.Name == description)
                    return (T)field.GetValue(null);
            }
        }

        throw new ArgumentException("Not found.", nameof(description));
        // Or return default(T);
    }
}

Usage:

var panda = EnumEx.GetValueFromDescription<Animal>("Giant Panda");

Solution 2

rather than extension methods, just try a couple of static methods

public static class Utility
{
    public static string GetDescriptionFromEnumValue(Enum value)
    {
        DescriptionAttribute attribute = value.GetType()
            .GetField(value.ToString())
            .GetCustomAttributes(typeof (DescriptionAttribute), false)
            .SingleOrDefault() as DescriptionAttribute;
        return attribute == null ? value.ToString() : attribute.Description;
    }

    public static T GetEnumValueFromDescription<T>(string description)
    {
        var type = typeof(T);
        if (!type.IsEnum)
            throw new ArgumentException();
        FieldInfo[] fields = type.GetFields();
        var field = fields
                        .SelectMany(f => f.GetCustomAttributes(
                            typeof(DescriptionAttribute), false), (
                                f, a) => new { Field = f, Att = a })
                        .Where(a => ((DescriptionAttribute)a.Att)
                            .Description == description).SingleOrDefault();
        return field == null ? default(T) : (T)field.Field.GetRawConstantValue();
    }
}

and use here

var result1 = Utility.GetDescriptionFromEnumValue(
    Animal.GiantPanda);
var result2 = Utility.GetEnumValueFromDescription<Animal>(
    "Lesser Spotted Anteater");

Solution 3

The solution works good except if you have a Web Service.

You would need to do the Following as the Description Attribute is not serializable.

[DataContract]
public enum ControlSelectionType
{
    [EnumMember(Value = "Not Applicable")]
    NotApplicable = 1,
    [EnumMember(Value = "Single Select Radio Buttons")]
    SingleSelectRadioButtons = 2,
    [EnumMember(Value = "Completely Different Display Text")]
    SingleSelectDropDownList = 3,
}

public static string GetDescriptionFromEnumValue(Enum value)
{
        EnumMemberAttribute attribute = value.GetType()
            .GetField(value.ToString())
            .GetCustomAttributes(typeof(EnumMemberAttribute), false)
            .SingleOrDefault() as EnumMemberAttribute;
        return attribute == null ? value.ToString() : attribute.Value;
}

Solution 4

Should be pretty straightforward, its just the reverse of your previous method;

public static int GetEnumFromDescription(string description, Type enumType)
{
    foreach (var field in enumType.GetFields())
    {
        DescriptionAttribute attribute
            = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))as DescriptionAttribute;
        if(attribute == null)
            continue;
        if(attribute.Description == description)
        {
            return (int) field.GetValue(null);
        }
    }
    return 0;
}

Usage:

Console.WriteLine((Animal)GetEnumFromDescription("Giant Panda",typeof(Animal)));

Solution 5

You can't extend Enum as it's a static class. You can only extend instances of a type. With this in mind, you're going to have to create a static method yourself to do this; the following should work when combined with your existing method GetDescription:

public static class EnumHelper
{
    public static T GetEnumFromString<T>(string value)
    {
        if (Enum.IsDefined(typeof(T), value))
        {
            return (T)Enum.Parse(typeof(T), value, true);
        }
        else
        {
            string[] enumNames = Enum.GetNames(typeof(T));
            foreach (string enumName in enumNames)
            {  
                object e = Enum.Parse(typeof(T), enumName);
                if (value == GetDescription((Enum)e))
                {
                    return (T)e;
                }
            }
        }
        throw new ArgumentException("The value '" + value 
            + "' does not match a valid enum name or description.");
    }
}

And the usage of it would be something like this:

Animal giantPanda = EnumHelper.GetEnumFromString<Animal>("Giant Panda");
Share:
228,948

Related videos on Youtube

fearofawhackplanet
Author by

fearofawhackplanet

Updated on September 16, 2020

Comments

  • fearofawhackplanet
    fearofawhackplanet over 3 years

    Possible Duplicate:
    Finding an enum value by its Description Attribute

    I have a generic extension method which gets the Description attribute from an Enum:

    enum Animal
    {
        [Description("")]
        NotSet = 0,
    
        [Description("Giant Panda")]
        GiantPanda = 1,
    
        [Description("Lesser Spotted Anteater")]
        LesserSpottedAnteater = 2
    }
    
    public static string GetDescription(this Enum value)
    {            
        FieldInfo field = value.GetType().GetField(value.ToString());
    
        DescriptionAttribute attribute
                = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
                    as DescriptionAttribute;
    
        return attribute == null ? value.ToString() : attribute.Description;
    }
    

    so I can do...

    string myAnimal = Animal.GiantPanda.GetDescription(); // = "Giant Panda"
    

    now, I'm trying to work out the equivalent function in the other direction, something like...

    Animal a = (Animal)Enum.GetValueFromDescription("Giant Panda", typeof(Animal));
    
  • fearofawhackplanet
    fearofawhackplanet over 13 years
    yes it's getting the right enum type that I'm a bit stuck on.
  • Keith G
    Keith G about 12 years
    If you add the "this" keyword in front of string ... public static T GetValueFromDescription<T>(this string description) ... it becomes an extension method and you can use syntax like: var x = "Giant Panda".GetValueFromDescription<Animal>();
  • Ren
    Ren almost 11 years
    How does one find if the description is not valid? with: var x = EnumEx.GetValueFromDescription<Animal>("Dinosaur"); I know it would throw an exception. But what would x contain?
  • nawfal
    nawfal almost 11 years
    @VenkatRenukaPrasad if it would throw anyway, then x cant have anything and you need not worry. Have an exception handling mechanism and handle it.
  • nawfal
    nawfal almost 11 years
    value.ToString() is expensive, do not call it twice (.. if it matters)...
  • nawfal
    nawfal almost 11 years
    This is logically wrong (though can work in sensible scenarios). For instance if you have enum like Animal { ("Giant Panda")GiantPanda, ("GiantPanda")Tiger } and you call GetEnumFromString("GiantPanda"), you will get GiantPanda back, but I expect Tiger back. Have a function to either read enum string, or its description. Mixing both is a bad API style and can confuse clients. Or may be its good style to prevent user mistakes :)
  • MEMark
    MEMark over 9 years
    @nawfal, expensive compared to what?
  • nawfal
    nawfal over 9 years
    @MEMark I dont remember what I was thinking then, but may be this
  • ErikE
    ErikE almost 9 years
    If you change the method to add where T : Enum just before the open curly brace, you won't have to check the typeof(T) at runtime.
  • max
    max almost 9 years
    @ErikE Enum cannot be specified as a constraint (msdn.microsoft.com/en-us/library/56b2hk61.aspx)
  • ATD
    ATD over 8 years
    @ErikE you can't do that in C#.
  • ErikE
    ErikE over 8 years
    @ATD You're right, and I had forgotten that at the time. However, it is supported in the framework, so you can use Fody.ExtraConstraints to get the same effect, fully compiled and working as if where T : Enum had been specified. The syntax is public void MethodWithEnumConstraint<[EnumConstraint] T>() {...} which gets compiled to public void MethodWithEnumConstraint<T>() where T: struct, Enum {...}.
  • vbguyny
    vbguyny about 8 years
    Code is great but forgot to mention that you need to include using System.ComponentModel;
  • Atta H.
    Atta H. over 6 years
    I used the same method for me, but as mentioned by @Keith as an extension method. It Worked
  • Damien Sawyer
    Damien Sawyer about 6 years
    Might want to do case insensitive comparisons instead like this. if (string.Equals(attribute.Description,description, StringComparison.InvariantCultureIgnoreCase)) return (T)field.GetValue(null); It caught me out.
  • DLeh
    DLeh about 6 years
    I've posted how you can convert this to the new c# 7.3 Enum type constraint here stackoverflow.com/questions/2787506/…
  • Ashish-BeJovial
    Ashish-BeJovial almost 6 years
    what is the namespace of EnumMemberAttribute?
  • Prince Tegaton
    Prince Tegaton almost 6 years
    perfect.. bravo!!!
  • Jasmine
    Jasmine over 5 years
    This is exactly what I am looking for. Two highlights I loved are, my enum also starts with 1. Secondly, its enummember as its wcf. Thank you so much :)
  • Dennis
    Dennis about 5 years
    To make the above code work better, change the line "foreach(var field in type.GetFields())" to "foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))". Otherwise in the else below, the name of the field is 'value__' instead of the real name.
  • Shahzad
    Shahzad over 4 years
    @AshishJain it's System.Runtime.Serialization