1

There are a lot of examples in which you can Get Enum by Custom attribute like here Get Enum from Description attribute

public static class EnumEx
{
    public static T GetValueFromDescription<T>(string description)
    {
        var type = typeof(T);
        if(!type.IsEnum) throw new InvalidOperationException();
        foreach(var field in type.GetFields())
        {
            var attribute = Attribute.GetCustomAttribute(field,
                typeof(DescriptionAttribute)) as DescriptionAttribute;
            if(attribute != null)
            {
                if(attribute.Description == description)
                    return (T)field.GetValue(null);
            }
            else
            {
                if(field.Name == description)
                    return (T)field.GetValue(null);
            }
        }
        throw new ArgumentException("Not found.", "description");
        // or return default(T);
    }
}

But here the problem is that you have to hardcode the attributeType i.e. typeof(DescriptionAttribute)) as DescriptionAttribute

How do i convert this example into Generic extension so that i dont have to hardcoded the CustomAttributeType.

Community
  • 1
  • 1
Waqar Ahmed
  • 1,414
  • 2
  • 15
  • 35
  • 1
    As an idea you can add another generic parameter to the method, but you should know the meaning and usage of input parameter to be able to search using it. For example now you can have this criteria `if(attribute.Description == description)` but what about when you passed a generic parameter? – Reza Aghaei Mar 21 '16 at 12:27
  • 2
    How would you translate this then: `attribute.Description` if `attribute` is not a `DescriptionAttribute`? – MakePeaceGreatAgain Mar 21 '16 at 12:28

3 Answers3

6

This will work for any attribute where you want to compare the values as strings:

public static TEnum GetValueFromAttribute<TEnum, TAttribute>
           (string text, Func<TAttribute, string> valueFunc) where TAttribute : Attribute
{ 
   // In newer versions of C# you can add where TEnum : Enum

   var type = typeof(TEnum);

   if(!type.IsEnum) {
       throw new InvalidOperationException();
   }

   foreach (var field in type.GetFields())
   {
       var attribute = Attribute.GetCustomAttribute(field, typeof(TAttribute)) as TAttribute;
       if(attribute != null)
       {
           if(valueFunc.Invoke(attribute) == text)
               return (TEnum)field.GetValue(null);
       }
       else
       {
           if(field.Name == text)
               return (TEnum)field.GetValue(null);
       }
   }

   throw new ArgumentException("Not found.", "text");
    // or return default(T);
}

Which you would then call like this:

 var value = GetValueFromAttribute<MyEnum, Description>("desc_text", a => a.Description);
stuartd
  • 70,509
  • 14
  • 132
  • 163
0

You could add an interface IDescription, that your attributes implement:

public interface IDescription
{
    string Description { get; }
}

public static class EnumEx
{
    public static T GetValueFromDescription<T, TAttribute>(string description) where TAttribute : Attribute, IDescription
    {
        var type = typeof(T);

        if (!type.IsEnum) throw new InvalidOperationException();

        foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))
        {
            var attribute = (IDescription)Attribute.GetCustomAttribute(field, typeof(TAttribute));

            if (attribute != null)
            {
                if (attribute.Description == description)
                {
                    return (T)field.GetValue(null);
                }
            }
            else
            {
                if (field.Name == description)
                {
                    return (T)field.GetValue(null);
                }
            }
        }

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

Or equivalent with a full base class:

public abstract class BaseDescriptionAttribute : Attribute
{
    public string Description { get; protected set; }
}

public static class EnumEx
{
    public static T GetValueFromDescription<T, TAttribute>(string description) where TAttribute : BaseDescriptionAttribute
    {
        var type = typeof(T);

        if (!type.IsEnum) throw new InvalidOperationException();

        foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))
        {
            var attribute = (BaseDescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(TAttribute));
xanatos
  • 109,618
  • 12
  • 197
  • 280
0

Add a new generic type

public static T GetValueFromDescription<T, K>(string description)

and use it in GetCustomerAttribute

var attribute = Attribute.GetCustomAttribute(field, typeof(K));
Marcello
  • 11
  • 1