Obtener atributos del valor de Enum

Resuelto Alex K asked hace 14 años • 27 respuestas

¿Me gustaría saber si es posible obtener atributos de los enumvalores y no del enummismo? Por ejemplo, supongamos que tengo lo siguiente enum:

using System.ComponentModel; // for DescriptionAttribute

enum FunkyAttributesEnum
{
    [Description("Name With Spaces1")]
    NameWithoutSpaces1,    
    [Description("Name With Spaces2")]
    NameWithoutSpaces2
}

Lo que quiero es dar el tipo de enumeración, producir 2 tuplas del valor de la cadena de enumeración y su descripción.

El valor fue fácil:

Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
    Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);

Pero, ¿cómo consigo que se complete el valor del atributo de descripción Tuple.Desc? Puedo pensar en cómo hacerlo si el Atributo pertenece a enumsí mismo, pero no sé cómo obtenerlo del valor de enum.

Alex K avatar Nov 26 '09 02:11 Alex K
Aceptado

Esto debería hacer lo que necesitas.

try
{
  var enumType = typeof(FunkyAttributesEnum);
  var memberInfos = 
  enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
  var enumValueMemberInfo = memberInfos.FirstOrDefault(m => 
  m.DeclaringType == enumType);
  var valueAttributes = 
  enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
  var description = ((DescriptionAttribute)valueAttributes[0]).Description;
}
catch
{
    return FunkyAttributesEnum.NameWithoutSpaces1.ToString()
}

Bryan Rowe avatar Nov 25 '2009 19:11 Bryan Rowe

Este fragmento de código debería brindarle un pequeño método de extensión agradable en cualquier enumeración que le permita recuperar un atributo genérico. Creo que es diferente a la función lambda anterior porque es más simple de usar y ligeramente: solo necesita pasar el tipo genérico.

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example><![CDATA[string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;]]></example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (attributes.Length > 0) ? (T)attributes[0] : null;
    }
}

El uso entonces sería:

string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;
AdamCrawford avatar Feb 14 '2012 11:02 AdamCrawford

Esta es una implementación genérica que utiliza una lambda para la selección.

public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
    where T : Attribute
{
    T attribute =
      enumeration
        .GetType()
        .GetMember(enumeration.ToString())
        .Where(member => member.MemberType == MemberTypes.Field)
        .FirstOrDefault()
        .GetCustomAttributes(typeof(T), false)
        .Cast<T>()
        .SingleOrDefault();

    if (attribute == null)
        return default(Expected);

    return expression(attribute);
}

Llámalo así:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
Scott Belchak avatar Feb 02 '2011 17:02 Scott Belchak

He fusionado un par de respuestas aquí para crear una solución un poco más extensible. Lo proporciono por si a alguien le resulta útil en el futuro. Publicación original aquí .

using System;
using System.ComponentModel;

public static class EnumExtensions {

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0 
          ? (T)attributes[0]
          : null;
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value) {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

}

Esta solución crea un par de métodos de extensión en Enum. El primero le permite utilizar la reflexión para recuperar cualquier atributo asociado con su valor. El segundo llama específicamente recupera DescriptionAttributey devuelve su Descriptionvalor.

Como ejemplo, considere usar el DescriptionAttributeatributo deSystem.ComponentModel

using System.ComponentModel;

public enum Days {
    [Description("Sunday")]
    Sun,
    [Description("Monday")]
    Mon,
    [Description("Tuesday")]
    Tue,
    [Description("Wednesday")]
    Wed,
    [Description("Thursday")]
    Thu,
    [Description("Friday")]
    Fri,
    [Description("Saturday")]
    Sat
}

Para utilizar el método de extensión anterior, ahora simplemente llamaría a lo siguiente:

Console.WriteLine(Days.Mon.ToName());

o

var day = Days.Mon;
Console.WriteLine(day.ToName());
Troy Alford avatar Oct 27 '2013 18:10 Troy Alford