433 votes

Comment obtenir la description d'un Enum C# à partir de sa valeur ?

J'ai un enum avec des attributs de description comme ceci :

public enum MyEnum
{
    Name1 = 1,
    [Description("Here is another")]
    HereIsAnother = 2,
    [Description("Last one")]
    LastOne = 3
}

J'ai trouvé ce bout de code pour récupérer la description basée sur un Enum.

public static string GetEnumDescription(Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];

    if (attributes != null && attributes.Any())
    {
        return attributes.First().Description;
    }

    return value.ToString();
}

Cela me permet d'écrire du code comme :

var myEnumDescriptions = from MyEnum n in Enum.GetValues(typeof(MyEnum))
                         select new { ID = (int)n, Name = Enumerations.GetEnumDescription(n) };

Ce que je veux faire, c'est que si je connais la valeur de l'enum (par exemple, 1), comment puis-je récupérer la description ? En d'autres termes, comment puis-je convertir un nombre entier en une "valeur d'énumération" à transmettre à ma méthode GetDescription ?

1 votes

(attributs != null) sera toujours vrai et else est redondant.

3 votes

L'espace de nom requis pour la description est System.ComponentModel

2 votes

409voto

Nicholas Piasecki Points 13681
int value = 1;
string description = Enumerations.GetEnumDescription((MyEnum)value);

Le type de données sous-jacentes par défaut pour un enum en C# est un int tu peux juste le lancer.

2 votes

Parfait. Exactement ce que je voulais. Je savais que ça allait être simple ! Maintenant, si stackoverflow me laissait accepter cette réponse... ça dit que je dois attendre 7 minutes.

106 votes

Pourquoi je ne trouve pas de classe Enumérations dans le cadre du .Net ?

88 votes

La classe Enumerations est quelque chose que la personne qui a posé la question a écrit elle-même, et la fonction GetEnumDescription() est dans la question.

120voto

Jon Skeet Points 692016

Mise à jour

La bibliothèque Unconstrained Melody n'est plus maintenue ; le support a été abandonné au profit de la bibliothèque Enums.NET .

Dans Enums.NET, vous utiliseriez :

string description = ((MyEnum)value).AsString(EnumFormat.Description);

Poste original

J'ai implémenté ceci d'une manière générique et sûre dans le cadre de Mélodie sans contrainte - que vous utiliseriez :

string description = Enums.GetDescription((MyEnum)value);

Ceci :

  • S'assure (avec des contraintes de type générique) que la valeur est réellement une valeur d'énumération.
  • Évite la mise en boîte dans votre solution actuelle
  • Met en cache toutes les descriptions pour éviter d'utiliser la réflexion à chaque appel.
  • Il dispose d'un certain nombre d'autres méthodes, notamment la possibilité d'analyser la valeur de la description.

Je réalise que la réponse principale était juste le casting d'un int à MyEnum mais si vous travaillez beaucoup sur les enums, il est bon de penser à utiliser Unconstrained Melody :)

0 votes

La "valeur" n'est-elle pas un int ? Donc, est-ce que Enums.GetDescription((MyEnum)value) ne fait pas simplement passer l'int à MyEnum ?

0 votes

@davekaro : Il convertit l'int en MyEnum - mais vous ne pourriez pas l'appeler avec un non-enum, y compris une référence "Enum". En gros, c'est comme votre code, mais avec un peu de magie générique.

2 votes

@JonSkeet Je ne vois pas cette méthode dans Enums.cs en code.google.com/p/unconstrained-melody/downloads/

105voto

Irish Points 369

J'ai rassemblé le code de la réponse acceptée dans une méthode d'extension générique, afin qu'il puisse être utilisé pour toutes sortes d'objets :

public static string DescriptionAttr<T>(this T source)
{
    FieldInfo fi = source.GetType().GetField(source.ToString());

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
        typeof(DescriptionAttribute), false);

    if (attributes != null && attributes.Length > 0) return attributes[0].Description;
    else return source.ToString();
}

En utilisant un enum comme dans le post original, ou toute autre classe dont la propriété est décorée avec l'attribut Description, le code peut être consommé comme ceci :

string enumDesc = MyEnum.HereIsAnother.DescriptionAttr();
string classDesc = myInstance.SomeProperty.DescriptionAttr();

5 votes

String classDesc = myInstance.SomeProperty.DescriptionAttr() ; Cela ne fonctionnera pas ! Disons que vous avez la classe Test { public int TestInt {get ; set;} }. Donc, si vous appelez new Test().TestInt.DescriptionAttr(), vous obtiendrez une exception de référence nulle - 0.GetType().GetField("0").

35voto

David Points 467

Pour faciliter son utilisation, j'ai écrit une extension générique :

public static string ToDescription<TEnum>(this TEnum EnumValue) where TEnum : struct
{
    return Enumerations.GetEnumDescription((Enum)(object)((TEnum)EnumValue));
}

maintenant je peux écrire :

        MyEnum my = MyEnum.HereIsAnother;
        string description = my.ToDescription();
        System.Diagnostics.Debug.Print(description);

Note : remplacez "Enumérations" ci-dessus par le nom de votre classe.

0 votes

To implique une conversion vers ce type. Peut-être que GetDescription serait un meilleur nom ?

8voto

itowlson Points 44174

Vous ne pouvez pas facilement le faire de manière générique : vous pouvez seulement convertir un entier en un type spécifique d'énumération. Comme Nicholas l'a montré, il s'agit d'un cast trivial si vous ne vous intéressez qu'à un seul type d'enum, mais si vous voulez écrire une méthode générique capable de gérer différents types d'enum, les choses se compliquent un peu. Vous voulez une méthode du type

public static string GetEnumDescription<TEnum>(int value)
{
  return GetEnumDescription((Enum)((TEnum)value));  // error!
}

mais cela entraîne une erreur de compilation indiquant que "int ne peut pas être converti en TEnum" (et si vous contournez cette erreur, que "TEnum ne peut pas être converti en Enum"). Vous devez donc tromper le compilateur en insérant des casts en objet :

public static string GetEnumDescription<TEnum>(int value)
{
  return GetEnumDescription((Enum)(object)((TEnum)(object)value));  // ugly, but works
}

Vous pouvez maintenant l'appeler pour obtenir une description de n'importe quel type d'enum :

GetEnumDescription<MyEnum>(1);
GetEnumDescription<YourEnum>(2);

0 votes

En quoi "GetEnumDescription<MonEnum>(1) ;" est-il meilleur que GetEnumDescription((MonEnum)1); ?

0 votes

@davekaro : Implémenté comme ça, ce n'est pas tellement mieux, mais une implémentation plus robuste basée sur les génériques pourrait le faire sans le cast explicite, donc vous ne risquez pas d'exceptions non gérées si le nombre ne correspond pas réellement à l'une des valeurs de l'enum.

1 votes

Intéressant. Juste pour clarifier pour les futurs lecteurs : On ne va pas obtenir une exception non gérée sur un cast explicite si le nombre ne correspond pas à l'une des valeurs de l'enum (vous pourriez dire "MyEnum value = (MyEnum)5 ;" et cette ligne s'exécutera très bien, mais vous feriez une bombe dans la première ligne de GetEnumDescription() comme implémenté dans la question originale (parce que GetField() retournera null car il ne peut trouver aucun champ correspondant avec cette valeur). (Pour se prémunir contre cela, il faudrait d'abord vérifier Enum.IsDefined() et retourner null ou une chaîne vide, ou simplement lancer nous-mêmes une ArgumentOutOfRangeException).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X