Get enum from enum attribute

23,044

Solution 1

Here's a helper method that should point you in the right direction.

protected Als GetEnumByStringValueAttribute(string value)
{
    Type enumType = typeof(Als);
    foreach (Enum val in Enum.GetValues(enumType))
    {
        FieldInfo fi = enumType.GetField(val.ToString());
        StringValueAttribute[] attributes = (StringValueAttribute[])fi.GetCustomAttributes(
            typeof(StringValueAttribute), false);
        StringValueAttribute attr = attributes[0];
        if (attr.Value == value)
        {
            return (Als)val;
        }
    }
    throw new ArgumentException("The value '" + value + "' is not supported.");
}

And to call it, just do the following:

Als result = this.GetEnumByStringValueAttribute<Als>(ComboBox.SelectedValue);

This probably isn't the best solution though as it's tied to Als and you'll probably want to make this code re-usable. What you'll probably want to strip out the code from my solution to return you the attribute value and then just use Enum.Parse as you are doing in your question.

Solution 2

I'm using the DescriptionAttribute from Microsoft and the following extension method:

public static string GetDescription(this Enum value)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }

    string description = value.ToString();
    FieldInfo fieldInfo = value.GetType().GetField(description);
    DescriptionAttribute[] attributes =
       (DescriptionAttribute[])
     fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

    if (attributes != null && attributes.Length > 0)
    {
        description = attributes[0].Description;
    }
    return description;
}

Solution 3

Here are a couple extension methods that I use for this exact purpose, I've rewritten these to use your StringValueAttribute, but like Oliver I use the DescriptionAttribute in my code.

    public static T FromEnumStringValue<T>(this string description) where T : struct {
        Debug.Assert(typeof(T).IsEnum);

        return (T)typeof(T)
            .GetFields()
            .First(f => f.GetCustomAttributes(typeof(StringValueAttribute), false)
                         .Cast<StringValueAttribute>()
                         .Any(a => a.Value.Equals(description, StringComparison.OrdinalIgnoreCase))
            )
            .GetValue(null);
    }

This can be made slightly more simple in .NET 4.5:

    public static T FromEnumStringValue<T>(this string description) where T : struct {
        Debug.Assert(typeof(T).IsEnum);

        return (T)typeof(T)
            .GetFields()
            .First(f => f.GetCustomAttributes<StringValueAttribute>()
                         .Any(a => a.Value.Equals(description, StringComparison.OrdinalIgnoreCase))
            )
            .GetValue(null);
    }

And to call it, just do the following:

Als result = ComboBox.SelectedValue.FromEnumStringValue<Als>();

Conversely, here's a function to get the string from an enum value:

    public static string StringValue(this Enum enumItem) {
        return enumItem
            .GetType()
            .GetField(enumItem.ToString())
            .GetCustomAttributes<StringValueAttribute>()
            .Select(a => a.Value)
            .FirstOrDefault() ?? enumItem.ToString();
    }

And to call it:

string description = Als.NietBeantwoord.StringValue()

Solution 4

Coming here from duplicate links of this highly upvoted question and answer, here is a method that works with C# 7.3's new Enum type constraint. Note that you also need to specify that it is also a struct so that you can make it the nullable TEnum? or else you will get an error.

public static TEnum? GetEnumFromDescription<TEnum>(string description)
    where TEnum : struct, Enum 
{
    var comparison = StringComparison.OrdinalIgnoreCase;
    foreach (var field in typeof(TEnum).GetFields())
    {
        var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
        if (attribute != null)
        {
            if (string.Compare(attribute.Description, description, comparison) == 0)
                return (TEnum)field.GetValue(null);
        }
        if (string.Compare(field.Name, description, comparison) == 0)
            return (TEnum)field.GetValue(null);
    }
    return null;
}

Solution 5

Not sure if I am missing something here, can you not do this,

Als temp = (Als)combo1.SelectedItem;
int t = (int)temp;
Share:
23,044
RubenHerman
Author by

RubenHerman

Updated on August 13, 2021

Comments

  • RubenHerman
    RubenHerman almost 3 years

    I've got

    public enum Als 
    {
        [StringValue("Beantwoord")] Beantwoord = 0,
        [StringValue("Niet beantwoord")] NietBeantwoord = 1,
        [StringValue("Geselecteerd")] Geselecteerd = 2,
        [StringValue("Niet geselecteerd")] NietGeselecteerd = 3,
    }
    

    with

    public class StringValueAttribute : Attribute
    {
        private string _value;
    
        public StringValueAttribute(string value)
        {
            _value = value;
        }
    
        public string Value
        {
            get { return _value; }
        }
    }
    

    And I would like to put the value from the item I selected of a combobox into a int:

    int i = (int)(Als)Enum.Parse(typeof(Als), (string)cboAls.SelectedValue); //<- WRONG
    

    Is this possible, and if so, how? (the StringValue matches the value selected from the combobox).

  • Daniel Hilgarth
    Daniel Hilgarth over 12 years
    This solution can easily be changed to be generic. Simply change all occurrences of Als to T and add a type argument named T to the method.
  • psycho
    psycho about 11 years
    Opposite of what OP asked since he wants enum from string and not string from enum, but that helped me a lot, thanks!
  • Ulysses Alves
    Ulysses Alves over 6 years
    @DanielHilgarth I tryied to do it but got error saying "The type parameter cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint" on the return line of the method. Would you have a practical example on how this could be solved?