Convertir Enum en String

163

Quelle est la méthode préférée pour convertir une énumération en chaîne dans .NET 3.5?

  • Enum.GetName
  • Enum.Format
  • ToString

Pourquoi devrais-je préférer l'un d'entre eux aux autres? Est-ce que l'un est plus performant?

Eric Weilnau
la source
10
J'ai cherché et je n'ai pas trouvé de doublon. Si vous pouvez fournir un lien, je supprimerai cette question.
Eric Weilnau
1
parfois, l'utilisation d'une instruction switch n'est pas la meilleure pratique (lorsque vous avez de grandes énumérations), vous pouvez utiliser Dict <> à la place
Guy L
1
Si vous voulez de meilleures performances, vous pouvez utiliser la classe décrite dans cet article codeproject.com/KB/dotnet/enum.aspx . L'utilisation ressemblera à ceci Enum <YourEnum> .ToString (yourValue) ou Enum <YourEnum> .ToString ((int) yourValue)
ideafixxxer
5
Coder pour ne pas casser la dotfuscation est la quintessence de la queue qui remue le chien. Les producteurs de logiciels ne pensent pas: "Faisons une excellente application pour que dotfuscator ait quelque chose à faire." Dofuscator existe pour faciliter le développement de logiciels. S'il ne peut pas faire ça ... peut-il!
micahhoover

Réponses:

127

Depuis C # 6, la meilleure façon d'obtenir le nom d'une énumération est le nouvel nameofopérateur:

nameof(MyEnum.EnumValue);

// Ouputs
> "EnumValue"

Cela fonctionne au moment de la compilation, l'énumération étant remplacée par la chaîne dans le résultat compilé, ce qui signifie que c'est le moyen le plus rapide possible.

Toute utilisation de noms enum interfère avec l'obscurcissement du code, si vous considérez que l'obfuscation des noms enum vaut la peine ou est importante - c'est probablement une toute autre question.

Keith
la source
11
Cela mérite plus d'attention. Nonobstant la limitation évidente, c'est-à-dire l'exigence d'une entrée au moment de la compilation. À mon avis, cela devrait être préféré dans la mesure du possible . «Renommer» et «trouver toutes les références» en tiennent également compte, évitant potentiellement les chaînes magiques et les constantes en double.
Timo
1
Donc, je suppose que cela ne fonctionnera pas lorsque la valeur enum est définie au moment de l'exécution? Ex: MyEnum variableEnum; variableEnum = setEnumValueMethod (); nameof (variableEnum);
Maxter
1
@ Maxter non, comme ce nameof(variableEnum)sera "variableEnum". Il reflète (au moment de la construction) le nom du champ / propriété / paramètre / variable et non la valeur .
Keith
vous. malheureusement ne fonctionne pas si vous faites ceci: var someEnumvalue = SomeEnum.FooBar; nameof (someEnumvalue);
Squably
1
@Squiblement oui, cela reviendra "someEnumValue", alors que vous auriez besoin nameof(SomeEnum.FooBar)de l'obtenir "FooBar".
Keith
93

Fonctionne pour notre projet ...

public static String convertToString(this Enum eff)
{
    return Enum.GetName(eff.GetType(), eff);
}

public static EnumType converToEnum<EnumType>(this String enumValue)  
{
    return (EnumType) Enum.Parse(typeof(EnumType), enumValue);
}
Sumtraveller
la source
7
Enum.GetName prend la valeur comme argument d'objet. Cela signifie que la valeur sera encadrée et cela gaspillera des ressources CPU sur l'allocation et sur le ramasse-miettes. Si cela est fait beaucoup de temps, Enum.GetName aura un débit beaucoup plus faible que la mise en cache des valeurs dans un dictionnaire et la recherche du nom là-bas.
Ran
@Ran alors quelle est la solution, laquelle utiliser à la place?
shaijut
Cela devrait être la réponse
Squably
rend mon projet plus lent. toString () est plus rapide.
d2k2
29

Dans mes tests, Enum.GetNamec'était plus rapide et avec une marge décente. ToStringAppels en interne Enum.GetName. De la source pour .NET 4.0, l'essentiel:

public override String ToString()
{
     return Enum.InternalFormat((RuntimeType)GetType(), GetValue());
}

private static String InternalFormat(RuntimeType eT, Object value)
{
    if (!eT.IsDefined(typeof(System.FlagsAttribute), false))
    {
        String retval = GetName(eT, value); //<== the one
        if (retval == null)
            return value.ToString();
        else
            return retval;
    }
    else
    {
        return InternalFlagsFormat(eT, value);
    }
}

Je ne peux pas dire que c'est la raison avec certitude, mais les tests indiquent que l'un est plus rapide que l'autre. Les deux appels impliquent de la boxe (en fait, ce sont des appels de réflexion, vous récupérez essentiellement les noms de champs) et peuvent être lents à votre goût.

Configuration du test : enum avec 8 valeurs, non. d'itérations = 1000000

Résultat : Enum.GetName => 700 ms, ToString => 2000 ms

Si la vitesse n'est pas perceptible, je ne m'en soucierais pas et l'utiliserais ToStringcar elle offre un appel beaucoup plus propre. Contraste

Enum.GetName(typeof(Bla), value)

avec

value.ToString()
nawfal
la source
25

Énumération.GetName (...)

C'est la méthode la plus élégante qui lui soit destinée.

var enumValueString = Enum.GetName(typeof (MyEnum), MyEnum.MyValue);

Bien que je ne vois aucun problème avec l'appel .ToString()car il est simplement plus court.

var enumValueString = MyEnum.MyValue.ToString();

Avec la nouvelle syntaxe C # 6, vous pouvez utiliser:

nameof(MyEnum.MyValue)
Andrei
la source
20

Tous ces éléments finissent par appeler en interne une méthode appelée InternalGetValueAsString. La différence entre ToStringet GetNameserait qu'il GetNamefaut d'abord vérifier quelques choses:

  1. Le type que vous avez entré n'est pas nul.
  2. Le type que vous avez entré est en fait une énumération.
  3. La valeur que vous avez transmise n'est pas nulle.
  4. La valeur que vous avez transmise est d'un type qu'une énumération peut réellement utiliser comme type sous-jacent, ou du type de l'énumération elle-même. Il utilise GetTypela valeur pour vérifier cela.

.ToStringn'a pas à s'inquiéter de l'un des problèmes ci-dessus, car il est appelé sur une instance de la classe elle-même, et non sur une version passée, par conséquent, en raison du fait que la .ToStringméthode n'a pas les mêmes problèmes de vérification en tant que méthodes statiques, je conclurais que .ToStringc'est le moyen le plus rapide d'obtenir la valeur sous forme de chaîne.

David Morton
la source
2
où avez-vous vérifié ces derniers? Quelle était la version d'assemblage? J'obtiens des résultats très différents.
nawfal
17

Le mieux que je puisse trouver est cette question sans rapport sur MSDN , qui contient un extrait de code XML qui répond à cette question. Chacune de ces méthodes partage le même défaut: elles appellent enum.toString(), ce qui ne fonctionne pas correctement lors de l'utilisation de Dotfuscation . D'autres préoccupations semblent concerner la boxe indirecte (GetName et Format). Malheureusement, je ne trouve aucune raison de performances pour utiliser l'un des éléments ci-dessus.

Paraphrasant de l' extrait de code XML ,

Passer une énumération encadrée à string.Format () ou à toute autre fonction peut entraîner l' enum.ToString()appel. Cela posera des problèmes lors de Dotfuscating. Vous ne devriez pas utiliser enum.ToString(), enum.GetNames(), enum.GetName(), enum.Format()ou enum.Parse()pour convertir un ENUM en une chaîne. Au lieu de cela, utilisez une instruction switch et internationalisez également les noms si nécessaire.

jpaugh
la source
16

Enum.GetName()

Format()est vraiment juste un wrapper GetName()avec des fonctionnalités de formatage (ou InternalGetValueAsString()pour être exact). ToString()est à peu près le même que Format(). Je pense que GetName()c'est la meilleure option car il est tout à fait évident ce que cela fait pour quiconque lit la source.

Tamas Czinege
la source
8

Je crée une méthode d'extension "Description" et l'attache à l'énumération afin que je puisse obtenir une dénomination vraiment conviviale qui inclut des espaces et des casse. Je n'ai jamais aimé utiliser la valeur enum elle-même comme texte affichable car c'est quelque chose que les développeurs utilisent pour créer un code plus lisible. Il n'est pas destiné à des fins d'affichage de l'interface utilisateur. Je veux pouvoir changer l'interface utilisateur sans passer par et changer les énumérations partout.

DansesAvecBambou
la source
6

Je ne sais pas quelle est la méthode "préférée" (demandez à 100 personnes et obtenez 100 opinions différentes) mais faites ce qui est le plus simple et ce qui fonctionne. GetNamefonctionne mais nécessite beaucoup plus de frappes. ToString()semble très bien faire le travail.

Perry Neal
la source
1

Pour les aficionados de VB:

EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)
GlennG
la source
0

Cela fonctionnerait aussi.

    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();
Nic
la source
0

ToString()donne le résultat le plus évident du point de vue de la lisibilité, tandis que l'utilisation Enum.GetName()nécessite un peu plus d'analyse mentale pour comprendre rapidement ce qu'il essaie de faire (à moins que vous ne voyiez le modèle tout le temps).

Du point de vue de la performance pure, comme déjà indiqué dans la réponse de @ nawfal, Enum.GetName()c'est mieux.

Si la performance est vraiment votre objectif, il serait encore mieux de fournir une recherche au préalable (en utilisant un dictionnaire ou un autre mappage).

En C ++ / CLI, cela ressemblerait à

Dictionary<String^, MyEnum> mapping;
for each (MyEnum field in Enum::GetValues(MyEnum::typeid))
{
    mapping.Add(Enum::GetName(MyEnum::typeid), field);
}

Comparaison utilisant une énumération de 100 éléments et 1000000 itérations:

Enum.GetName: ~ 800ms
.ToString (): ~ 1600ms Mappage du
dictionnaire: ~ 250ms

John Go-Soco
la source
-3

Simple: énumérer les noms dans une liste:

List<String> NameList = Enum.GetNames(typeof(YourEnumName)).Cast<string>().ToList()
Brian
la source
Salut @Brian, je ne pense pas que vous ayez besoin de diffuser la sortie de GetNames ()
Nic