web-dev-qa-db-fra.com

Obtenir l'énumération de l'attribut enum

J'ai

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

avec 

public class StringValueAttribute : Attribute
{
    private string _value;

    public StringValueAttribute(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }
}

Et je voudrais mettre la valeur de l'élément que j'ai sélectionné d'une liste déroulante dans un int:

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

Est-ce possible, et si oui comment? (la StringValue correspond à la valeur sélectionnée dans la liste déroulante).

32
RubenHerman

Voici une méthode d'assistance qui devrait vous orienter dans la bonne 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.");
}

Et pour l'appeler, procédez comme suit:

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

Ce n'est probablement pas la meilleure solution car elle est liée à Als et vous voudrez probablement rendre ce code réutilisable. Vous voudrez probablement supprimer le code de ma solution pour vous renvoyer la valeur de l'attribut, puis utilisez simplement Enum.Parse comme vous le faites dans votre question.

21
djdd87

J'utilise le DescriptionAttribute de Microsoft et la méthode d'extension suivante:

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;
}
11
Oliver

Voici quelques méthodes d’extension que j’utilise dans ce but précis. Je les ai réécrites pour utiliser votre StringValueAttribute, mais comme Oliver j’utilise le DescriptionAttribute dans mon 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);
    }

Cela peut être légèrement simplifié dans .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);
    }

Et pour l'appeler, procédez comme suit:

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

Inversement , voici une fonction pour obtenir la chaîne à partir d'une valeur enum:

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

Et pour l'appeler:

string description = Als.NietBeantwoord.StringValue()
6
joshperry

Je ne sais pas si quelque chose me manque ici, ne pouvez-vous pas le faire,

Als temp = (Als)combo1.SelectedItem;
int t = (int)temp;
1
theraneman

En venant ici de liens en double de cette question et cette réponse très appréciées , voici une méthode qui fonctionne avec la nouvelle contrainte de type Enum de C # 7.3. Notez que vous devez également spécifier qu'il s'agit également d'une struct pour pouvoir en faire le nullable TEnum? sinon vous obtiendrez une erreur.

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;
}
1
DLeh

Pour analyser une valeur de chaîne en fonction des valeurs d'attribut appliquées aux membres enum, je vous recommande d'utiliser ma bibliothèque Enums.NET open source.

Pour un attribut personnalisé tel que StringValueAttribute, vous le feriez.

Enregistrez et stockez une EnumFormat personnalisée pour StringValueAttribute.Value.

Format = Enums.RegisterCustomEnumFormat(m => m.Attributes.Get<StringValueAttribute>()?.Value);

Ensuite, utilisez la personnalisation EnumFormat.

Als result = Enums.Parse<Als>("Niet beantwoord", Format); // result == Als.NietBeantwoord

Si vous utilisiez plutôt un attribut intégré tel que DescriptionAttribute , vous pouvez simplement le faire.

Als result = Enums.Parse<Als>("Niet beantwoord", EnumFormat.Description);

Si cela vous intéresse, voici comment vous obtenez la valeur de chaîne associée à une valeur enum.

string value = Als.NietBeantwoord.AsString(Format); // value == "Niet beantwoord"
0
TylerBrinkley