Question Représentation sous forme de chaîne d'un Enum


J'ai l'énumération suivante:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

Le problème est cependant que j'ai besoin du mot "FORMS" quand je demande AuthenticationMethod.FORMS et non l'identifiant 1.

J'ai trouvé la solution suivante pour ce problème (lien):

Je dois d'abord créer un attribut personnalisé appelé "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

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

    public string Value
    {
        get { return _value; }
    }

}

Ensuite, je peux ajouter cet attribut à mon énumérateur:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

Et bien sûr j'ai besoin de quelque chose pour récupérer cette StringValue:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Bon maintenant j'ai les outils pour obtenir une valeur de chaîne pour un énumérateur. Je peux alors l'utiliser comme ceci:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

Ok maintenant, tout cela fonctionne comme un charme, mais je trouve qu'il y a beaucoup de travail. Je me demandais s'il y avait une meilleure solution pour cela.

J'ai aussi essayé quelque chose avec un dictionnaire et des propriétés statiques mais ce n'était pas mieux non plus.


823
2018-01-08 14:15


origine


Réponses:


Essayer type-safe-enum modèle.

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Mettre à jour La conversion de type explicite (ou implicite) peut être effectuée par

  • ajouter un champ statique avec le mappage

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • n.b. Pour que l'initialisation des champs "enum member" ne lève pas une exception NullReferenceException lors de l'appel du constructeur d'instance, veillez à placer le champ Dictionary avant les champs "enum member" dans votre classe. Cela est dû au fait que les initialiseurs de champs statiques sont appelés dans l'ordre de déclaration, et avant le constructeur statique, créant la situation étrange et nécessaire mais confuse que le constructeur d'instance peut être appelé avant que tous les champs statiques soient initialisés et avant que le constructeur statique soit appelé.
  • remplir cette cartographie dans le constructeur de l'instance

    instance[name] = this;
    
  • et en ajoutant opérateur de conversion de type défini par l'utilisateur

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    

814
2018-01-08 14:29



Utiliser la méthode

Enum.GetName(Type MyEnumType,  object enumvariable)  

comme dans (Supposons Shipper est un Enum défini)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

Il y a un tas d'autres méthodes statiques sur la classe Enum qui méritent d'être étudiées aussi ...


209
2018-01-08 14:19



Vous pouvez référencer le nom plutôt que la valeur en utilisant ToString ()

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

La documentation est ici:

http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

... et si vous nommez vos énumérations dans Pascal Case (comme je le fais - comme ThisIsMyEnumValue = 1 etc.) alors vous pouvez utiliser une expression rationnelle très simple pour imprimer le formulaire amical:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

qui peut facilement être appelé à partir de n'importe quelle chaîne:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

Les sorties:

Convertir ma phrase de cas fou de Pascal en cas amical

Cela évite de courir tout autour des maisons en créant des attributs personnalisés et en les attachant à vos énumérations ou en utilisant des tables de recherche pour marier une valeur enum avec une chaîne amicale et mieux, elle s'auto-gère et peut être utilisée sur n'importe quelle chaîne plus réutilisable. Bien sûr, cela ne vous permet pas d'avoir différent nom convivial que votre énumération que votre solution fournit.

J'apprécie cependant votre solution originale pour des scénarios plus complexes. Vous pourriez pousser votre solution un peu plus loin et faire de votre GetStringValue une méthode d'extension de votre énumération, et vous n'auriez plus besoin de la référencer comme StringEnum.GetStringValue ...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

Vous pouvez alors y accéder facilement directement à partir de votre instance enum:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());

74
2018-01-08 14:20



Malheureusement, la réflexion pour obtenir des attributs sur enums est assez lente:

Voir cette question: Quelqu'un sait-il un moyen rapide d'accéder aux attributs personnalisés sur une valeur enum?

le .ToString() est assez lent sur les enums aussi.

Vous pouvez cependant écrire des méthodes d'extension pour des énumérations:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

Ce n'est pas génial, mais il sera rapide et ne nécessitera pas de réflexion pour les attributs ou le nom du champ.


Mise à jour de C # 6

Si vous pouvez utiliser C # 6 alors le nouveau nameof opérateur travaille pour enums, donc nameof(MyEnum.WINDOWSAUTHENTICATION) sera converti en "WINDOWSAUTHENTICATION" à compiler le temps, ce qui en fait le moyen le plus rapide d'obtenir des noms enum.

Notez que cela convertira l'enum explicite en une constante inline, donc cela ne fonctionne pas pour les énumérations que vous avez dans une variable. Alors:

nameof(AuthenticationMethod.FORMS) == "FORMS"

Mais...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"

63
2018-02-11 00:15



J'utilise une méthode d'extension:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

Maintenant décorer le enum avec:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

Quand vous appelez

AuthenticationMethod.FORMS.ToDescription() tu auras "FORMS".


52
2017-09-06 15:50



Utilisez simplement le ToString() méthode

public enum any{Tomato=0,Melon,Watermelon}

Pour référencer la chaîne Tomato, utilisez juste

any.Tomato.ToString();

36
2018-01-08 14:30



J'utilise l'attribut Description de l'espace de noms System.ComponentModel. Décorez simplement l'énumération puis utilisez ce code pour le récupérer:

public static string GetDescription<T>(this object enumerationValue)
            where T : struct
        {
            Type type = enumerationValue.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
            }

            //Tries to find a DescriptionAttribute for a potential friendly name
            //for the enum
            MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0)
                {
                    //Pull out the description value
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }
            //If we have no description attribute, just return the ToString of the enum
            return enumerationValue.ToString();

        }

Par exemple:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

Ce code répond bien aux énumérations où vous n'avez pas besoin d'un "nom convivial" et retournera juste le .ToString () de l'énumération.


26
2017-09-22 20:46



Solution très simple à cela avec .Net 4.0 et ci-dessus. Aucun autre code n'est nécessaire.

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

Pour obtenir la chaîne à propos de simplement utiliser:

MyStatus.Active.ToString("f");

ou

MyStatus.Archived.ToString("f");`

La valeur sera "Actif" ou "Archivé".

Pour voir les différents formats de chaînes (le "f" ci-dessus) lors de l'appel Enum.ToString regarde ça Chaînes de format d'énumération page


22
2018-01-20 21:13