web-dev-qa-db-fra.com

Représentation de chaîne d'un enum

J'ai l'énumération suivante:

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

Cependant, le problème est que j'ai besoin du mot "FORMS" lorsque je demande AuthenticationMethod.FORMS et non de l'id 1.

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

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 ensuite l'utiliser comme ça:

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

Bon maintenant tout cela fonctionne comme un charme mais je le trouve 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.

885
user29964

Essayez type-safe-enum pattern.

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

}

Update La conversion de type explicite (ou implicite) peut être effectuée en:

  • ajout de champs statiques avec mapping

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • nb Pour que l'initialisation des champs "membre enum" ne génère pas d'exception NullReferenceException lors de l'appel du constructeur de l'instance, veillez à placer le champ Dictionnaire avant les champs "membre enum" de votre classe. En effet, les initialiseurs de champs statiques sont appelés dans l'ordre des déclarations, et avant le constructeur statique, ce qui crée la situation étrange et nécessaire, mais source de confusion, selon laquelle le constructeur d'instance peut être appelé avant que tous les champs statiques aient été initialisés et avant d'être appelés.
  • remplir ce mappage dans le constructeur d'instance

    instance[name] = this;
    
  • et ajout de 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();
    }
    
856
Jakub Šturc

Méthode d'utilisation

Enum.GetName(Type MyEnumType,  object enumvariable)  

comme dans (supposons que Shipper soit un enum défini)

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

Il y a beaucoup d'autres méthodes statiques sur la classe Enum qui valent la peine d'être explorées aussi ...

224
Charles Bretana

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 enums dans Pascal Case (comme je le fais - tel que ThisIsMyEnumValue = 1 etc.), vous pouvez utiliser une regex très simple pour imprimer le formulaire convivial:

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

qui peut facilement être appelé depuis n'importe quelle chaîne:

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

Les sorties:

Convertir la phrase de mon cas Crazy Pascal en un cas amical

Cela évite de créer des attributs personnalisés et de les associer à vos enums ou d'utiliser des tables de recherche pour associer une valeur d'enum avec une chaîne conviviale. Mieux encore, elle est auto-gérée et peut être utilisée sur toute chaîne de cas Pascal qui est infiniment plus réutilisable. Bien sûr, cela ne vous permet pas d'avoir un nom différent différent de votre énumération fournie par votre solution.

J'aime votre solution d'origine, bien que pour des scénarios plus complexes. Vous pouvez aller plus loin dans votre solution et faire de votre GetStringValue une méthode d'extension de votre enum et vous n'aurez alors pas besoin de le 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 pourrez alors y accéder facilement directement à partir de votre instance enum:

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

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

Voir cette question: Quelqu'un connaît un moyen rapide d'obtenir des attributs personnalisés sur une valeur enum?

La .ToString() est également assez lente sur les énumérations.

Vous pouvez cependant écrire des méthodes d'extension pour les é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 sera rapide et ne nécessitera pas la réflexion pour les attributs ou le nom du champ.


Mise à jour de C # 6

Si vous pouvez utiliser C # 6, le nouvel opérateur nameof fonctionne pour les énumérations. Ainsi, nameof(MyEnum.WINDOWSAUTHENTICATION) sera converti en "WINDOWSAUTHENTICATION" à au moment de la compilation . , ce qui en fait le moyen le plus rapide d’obtenir des noms enum.

Notez que cela convertira l'énumération explicite en une constante incorporée, donc cela ne fonctionnera pas pour les énumérations que vous avez dans une variable. Alors:

nameof(AuthenticationMethod.FORMS) == "FORMS"

Mais...

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

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écorez le enum avec:

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

Quand vous appelez

AuthenticationMethod.FORMS.ToDescription() vous obtiendrez "FORMS".

59
Mangesh Pimpalkar

Il suffit d'utiliser la méthode ToString()

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

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

any.Tomato.ToString();
40
chepe

Solution très simple à cela avec .Net 4.0 et supérieur. 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îne (le "f" d'en haut) lors de l'appel de Enum.ToString voyez ceci Chaînes de format d'énumération page

28
David C

J'utilise l'attribut Description de l'espace de noms System.ComponentModel. Décorez simplement l'énum, ​​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 convient parfaitement aux enum où vous n'avez pas besoin d'un "Nom convivial" et renverra uniquement le .ToString () de l'énum.

28
Ray Booysen

J'aime beaucoup la réponse de Jakub Šturc, mais son inconvénient est que vous ne pouvez pas l'utiliser avec une déclaration de changement de cas. Voici une version légèrement modifiée de sa réponse qui peut être utilisée avec une instruction switch:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

Vous bénéficiez ainsi de tous les avantages de la réponse de Jakub Šturc. De plus, nous pouvons l’utiliser avec une instruction switch telle que:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}
25
deadlydog

J'utilise une combinaison de plusieurs des suggestions ci-dessus, associée à une mise en cache. Maintenant, j'ai eu l'idée d'un code que j'ai trouvé quelque part sur le net, mais je ne me souviens pas non plus d'où je l'ai eu ou je l'ai trouvé. Donc, si quelqu'un trouve quelque chose qui ressemble, veuillez commenter avec l'attribution.

Quoi qu'il en soit, l'utilisation implique les convertisseurs de types, donc si vous vous liez à l'interface utilisateur, cela "fonctionne". Vous pouvez étendre le motif de Jakub pour une recherche rapide du code en initialisant le convertisseur de type dans les méthodes statiques.

L'utilisation de base ressemblerait à ceci

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
    // The custom type converter will use the description attribute
    [Description("A custom description")]
    ValueWithCustomDescription,

   // This will be exposed exactly.
   Exact
}

Le code du convertisseur de type enum personnalisé est le suivant:

public class CustomEnumTypeConverter<T> : EnumConverter
    where T : struct
{
    private static readonly Dictionary<T,string> s_toString = 
      new Dictionary<T, string>();

    private static readonly Dictionary<string, T> s_toValue = 
      new Dictionary<string, T>();

    private static bool s_isInitialized;

    static CustomEnumTypeConverter()
    {
        System.Diagnostics.Debug.Assert(typeof(T).IsEnum,
          "The custom enum class must be used with an enum type.");
    }

    public CustomEnumTypeConverter() : base(typeof(T))
    {
        if (!s_isInitialized)
        {
            Initialize();
            s_isInitialized = true;
        }
    }

    protected void Initialize()
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            string description = GetDescription(item);
            s_toString[item] = description;
            s_toValue[description] = item;
        }
    }

    private static string GetDescription(T optionValue)
    {
        var optionDescription = optionValue.ToString();
        var optionInfo = typeof(T).GetField(optionDescription);
        if (Attribute.IsDefined(optionInfo, typeof(DescriptionAttribute)))
        {
            var attribute = 
              (DescriptionAttribute)Attribute.
                 GetCustomAttribute(optionInfo, typeof(DescriptionAttribute));
            return attribute.Description;
        }
        return optionDescription;
    }

    public override object ConvertTo(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, 
       object value, Type destinationType)
    {
        var optionValue = (T)value;

        if (destinationType == typeof(string) && 
            s_toString.ContainsKey(optionValue))
        {
            return s_toString[optionValue];
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, object value)
    {
        var stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue) && s_toValue.ContainsKey(stringValue))
        {
            return s_toValue[stringValue];
        }

        return base.ConvertFrom(context, culture, value);
    }
}

}

13
Steve Mitcham

Dans votre question, vous n'avez jamais dit que vous aviez besoin de la valeur numérique de l'énum où que vous soyez.

Si vous n'avez pas besoin d'une énumération de type chaîne (qui n'est pas un type intégral, vous ne pouvez donc pas constituer une base d'enum), voici une solution:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

vous pouvez utiliser la même syntaxe que enum pour le référencer

if (bla == AuthenticationMethod.FORMS)

Ce sera un peu plus lent qu'avec des valeurs numériques (comparer des chaînes au lieu de nombres), mais du côté positif, la réflexion (lente) n'est pas utilisée pour accéder à la chaîne.

12
ILIA BROUDNO

Mise à jour: En visitant cette page, 8 ans plus tard, après ne pas avoir touché C # pendant longtemps, ma réponse ne semble plus être la meilleure. J'aime beaucoup la solution de convertisseur liée aux fonctions d'attribut.

Si vous lisez ceci, assurez-vous également de consulter les autres réponses.
(indice: ils sont au-dessus de celui-ci)


Comme la plupart d’entre vous, j’ai beaucoup aimé le choix réponse de Jakub Šturc , mais je déteste aussi le fait de copier-coller du code et d’essayer de le faire le moins possible.

J'ai donc décidé que je voulais une classe EnumBase à partir de laquelle la plupart des fonctionnalités sont héritées/intégrées, me permettant de me concentrer sur le contenu plutôt que sur le comportement.

Le principal problème de cette approche repose sur le fait que, bien que les valeurs Enum soient des instances sécurisées pour le type, l’interaction se fait avec l’implémentation statique du type de classe Enum. Donc, avec un peu d’aide magique des génériques, je pense que j’ai enfin obtenu le bon mélange. J'espère que quelqu'un trouvera cela aussi utile que moi.

Je vais commencer par l'exemple de Jakub, mais en utilisant l'héritage et les génériques:

public sealed class AuthenticationMethod : EnumBase<AuthenticationMethod, int>
{
    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)
        : base( Value, Name ) { }
    public new static IEnumerable<AuthenticationMethod> All
    { get { return EnumBase<AuthenticationMethod, int>.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

Et voici la classe de base:

using System;
using System.Collections.Generic;
using System.Linq; // for the .AsEnumerable() method call

// E is the derived type-safe-enum class
// - this allows all static members to be truly unique to the specific
//   derived class
public class EnumBase<E, T> where E: EnumBase<E, T>
{
    #region Instance code
    public T Value { get; private set; }
    public string Name { get; private set; }

    protected EnumBase(T EnumValue, string Name)
    {
        Value = EnumValue;
        this.Name = Name;
        mapping.Add(Name, this);
    }

    public override string ToString() { return Name; }
    #endregion

    #region Static tools
    static private readonly Dictionary<string, EnumBase<E, T>> mapping;
    static EnumBase() { mapping = new Dictionary<string, EnumBase<E, T>>(); }
    protected static E Parse(string name)
    {
        EnumBase<E, T> result;
        if (mapping.TryGetValue(name, out result))
        {
            return (E)result;
        }

        throw new InvalidCastException();
    }
    // This is protected to force the child class to expose it's own static
    // method.
    // By recreating this static method at the derived class, static
    // initialization will be explicit, promising the mapping dictionary
    // will never be empty when this method is called.
    protected static IEnumerable<E> All
    { get { return mapping.Values.AsEnumerable().Cast<E>(); } }
    #endregion
}
11
Lockszmith

Comment j'ai résolu ceci en tant que méthode d'extension:

using System.ComponentModel;
public static string GetDescription(this Enum value)
{
    var descriptionAttribute = (DescriptionAttribute)value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(false)
        .Where(a => a is DescriptionAttribute)
        .FirstOrDefault();

    return descriptionAttribute != null ? descriptionAttribute.Description : value.ToString();
}

Enum:

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

Utilisation (où o.OrderType est une propriété portant le même nom que l'énum):

o.OrderType.GetDescription()

Ce qui me donne une chaîne de "Nouvelle carte" ou "Recharger" au lieu de la valeur enum réelle NewCard et Refill.

11
Sec

Je suis d'accord avec Keith, mais je ne peux pas voter (pour le moment).

J'utilise une méthode statique et une instruction swith pour retourner exactement ce que je veux. Dans la base de données, je stocke tinyint et mon code utilise uniquement l'énumération réelle. Les chaînes sont donc conformes aux exigences de l'interface utilisateur. Après de nombreux tests, nous avons obtenu les meilleures performances et le plus grand contrôle sur la sortie.

public static string ToSimpleString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "ComplexForms";
             break;
     }
}

public static string ToFormattedString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "Complex Forms";
             break;
     }
}

Toutefois, selon certains comptes, cela pourrait entraîner un cauchemar d’entretien et une certaine odeur de code. J'essaie de garder un œil sur les enums longs et nombreux, ou ceux qui changent fréquemment. Sinon, cela a été une excellente solution pour moi.

10
Tony Basallo

Si vous êtes venu ici pour implémenter un simple "Enum" mais dont les valeurs sont des chaînes plutôt que des entiers, voici la solution la plus simple:

    public sealed class MetricValueList
    {
        public static readonly string Brand = "A4082457-D467-E111-98DC-0026B9010912";
        public static readonly string Name = "B5B5E167-D467-E111-98DC-0026B9010912";
    }

La mise en oeuvre:

var someStringVariable = MetricValueList.Brand;
10
Grinn

Je voulais poster ceci en tant que commentaire sur le post cité ci-dessous, mais je ne pouvais pas parce que je n'ai pas assez de représentants - alors s'il vous plaît, ne votez pas à la baisse. Le code contenait une erreur et je voulais le signaler aux personnes essayant d'utiliser cette solution:

[TypeConverter(typeof(CustomEnumTypeConverter(typeof(MyEnum))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,
  // This will be exposed exactly.
  Exact
}

devrait être

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}

Brillant!

7
Paula Bean

Lorsque je suis confronté à ce problème, je tente d'abord de trouver les réponses aux questions suivantes:

  • Les noms de mes valeurs enum sont-ils suffisamment conviviaux ou dois-je fournir des noms plus conviviaux?
  • Dois-je faire l'aller-retour? C'est-à-dire, devrais-je prendre des valeurs de texte et les analyser en valeurs d'enum?
  • Est-ce quelque chose que je dois faire pour plusieurs enums de mon projet, ou juste un?
  • Quels types d'éléments d'interface utilisateur vais-je présenter ces informations - en particulier, vais-je être contraignant pour l'interface utilisateur ou utiliser des feuilles de propriétés?
  • Cela doit-il être localisable?

La méthode la plus simple consiste à utiliser Enum.GetValue (et à prendre en charge les allers-retours avec Enum.Parse). Comme le suggère Steve Mitcham, il est également souvent utile de créer une TypeConverter pour prendre en charge la liaison de l'interface utilisateur. (Il n'est pas nécessaire de créer une TypeConverter lorsque vous utilisez des feuilles de propriétés, ce qui est l'un des aspects les plus intéressants des feuilles de propriétés. Bien que le seigneur sache qu'elles ont leurs propres problèmes.)

En général, si les réponses aux questions ci-dessus suggèrent que cela ne fonctionnera pas, la prochaine étape consiste à créer et à peupler un Dictionary<MyEnum, string> statique, ou éventuellement un Dictionary<Type, Dictionary<int, string>>. J'ai tendance à ignorer l'étape intermédiaire Décorer-le-code-avec-les attributs, car ce qui revient généralement ensuite est le besoin de changer les valeurs amicales après le déploiement (souvent, mais pas toujours, à cause de la localisation).

7
Robert Rossney

Ma variante

public struct Colors
{
    private String current;

    private static string red = "#ff0000";
    private static string green = "#00ff00";
    private static string blue = "#0000ff";

    private static IList<String> possibleColors; 

    public static Colors Red { get { return (Colors) red; } }
    public static Colors Green { get { return (Colors) green; } }
    public static Colors Blue { get { return (Colors) blue; } }

    static Colors()
    {
        possibleColors = new List<string>() {red, green, blue};
    }

    public static explicit operator String(Colors value)
    {
        return value.current;
    }

    public static explicit operator Colors(String value)
    {
        if (!possibleColors.Contains(value))
        {
            throw new InvalidCastException();
        }

        Colors color = new Colors();
        color.current = value;
        return color;
    }

    public static bool operator ==(Colors left, Colors right)
    {
        return left.current == right.current;
    }

    public static bool operator !=(Colors left, Colors right)
    {
        return left.current != right.current;
    }

    public bool Equals(Colors other)
    {
        return Equals(other.current, current);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != typeof(Colors)) return false;
        return Equals((Colors)obj);
    }

    public override int GetHashCode()
    {
        return (current != null ? current.GetHashCode() : 0);
    }

    public override string ToString()
    {
        return current;
    }
}

Le code semble un peu moche, mais les utilisations de cette structure sont assez représentatives.

Colors color1 = Colors.Red;
Console.WriteLine(color1); // #ff0000

Colors color2 = (Colors) "#00ff00";
Console.WriteLine(color2); // #00ff00

// Colors color3 = "#0000ff"; // Compilation error
// String color4 = Colors.Red; // Compilation error

Colors color5 = (Colors)"#ff0000";
Console.WriteLine(color1 == color5); // True

Colors color6 = (Colors)"#00ff00";
Console.WriteLine(color1 == color6); // False

De plus, je pense que, si cela est nécessaire, la génération de code (T4, par exemple) pourrait être utilisée.

5
Razoomnick

Option 1:

public sealed class FormsAuth
{
     public override string ToString{return "Forms Authtentication";}
}
public sealed class WindowsAuth
{
     public override string ToString{return "Windows Authtentication";}
}

public sealed class SsoAuth
{
     public override string ToString{return "SSO";}
}

puis

object auth = new SsoAuth(); //or whatever

//...
//...
// blablabla

DoSomethingWithTheAuth(auth.ToString());

Option 2:

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

public class MyClass
{
    private Dictionary<AuthenticationMethod, String> map = new Dictionary<AuthenticationMethod, String>();
    public MyClass()
    {
         map.Add(AuthenticationMethod.FORMS,"Forms Authentication");
         map.Add(AuthenticationMethod.WINDOWSAUTHENTICATION ,"Windows Authentication");
         map.Add(AuthenticationMethod.SINGLESIGNON ,"SSo Authentication");
    }
}
4
Pablo Retyk

pour moi, l'approche pragmatique est la classe à l'intérieur de la classe, exemple:

public class MSEModel
{
    class WITS
    {
        public const string DATE = "5005";
        public const string TIME = "5006";
        public const string MD = "5008";
        public const string ROP = "5075";
        public const string WOB = "5073";
        public const string RPM = "7001";
... 
    }
4
harveyt

Si vous réfléchissez au problème que nous essayons de résoudre, ce n'est pas du tout une énumération dont nous avons besoin. Nous avons besoin d'un objet permettant d'associer un certain nombre de valeurs; autrement dit, définir une classe.

Le modèle enum-safe de Jakub Šturc est la meilleure option que je vois ici.

Regarde ça:

  • Il possède un constructeur privé, de sorte que seule la classe peut définir les valeurs autorisées.
  • C'est une classe scellée donc les valeurs ne peuvent pas être modifiées par héritage.
  • Il est compatible avec le type, ce qui permet à vos méthodes d’exiger uniquement ce type.
  • L'accès aux valeurs n'entraîne aucune perte de performances de réflexion.
  • Enfin, il peut être modifié pour associer plus de deux champs, par exemple un nom, une description et une valeur numérique.
4
Harvo

Beaucoup de bonnes réponses ici mais dans mon cas n'ont pas résolu ce que je voulais d'un "enum string", qui était:

  1. Utilisable dans une instruction switch, par exemple switch (myEnum)
  2. Peut être utilisé dans les paramètres de fonction, par exemple. toto (type myEnum)
  3. Peut être référencé par exemple myEnum.FirstElement
  4. Je peux utiliser des chaînes, par exemple. foo ("FirstElement") == foo (myEnum.FirstElement)

1,2 et 4 peuvent en fait être résolus avec un C # Typedef d'une chaîne (puisque les chaînes sont commutables en c #)

3 peut être résolu par des chaînes de caractères statiques. Donc, si vous avez les mêmes besoins, voici l’approche la plus simple:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }


    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

Cela permet par exemple:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

et

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

Où CreateType peut être appelé avec une chaîne ou un type. Cependant, l'inconvénient est que toute chaîne est automatiquement une énumération valide, cela pourrait être modifié, mais il faudrait alors une sorte de fonction init ... ou peut-être les rendre explicites en interne?

Maintenant, si une valeur int était importante pour vous (peut-être pour la vitesse de comparaison), vous pourriez utiliser quelques idées de Jakub Šturc, une réponse fantastique et faire quelque chose d'un bit fou, voici ce que je tente de faire:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }


    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

mais bien sûr "Types bob = 4;" cela n'aurait aucun sens si vous ne les aviez pas initialisés en premier, ce qui viderait en quelque sorte le point ...

Mais en théorie, TypeA == TypeB serait plus rapide ...

3
chrispepper1989

Si je vous ai bien compris, vous pouvez simplement utiliser .ToString () pour récupérer le nom de l’énum à partir de la valeur (en supposant qu’il a déjà été converti en Enum); Si vous aviez l'int naked (disons d'une base de données ou quelque chose comme ça), vous pouvez d'abord le lancer dans l'énum. Les deux méthodes ci-dessous vous donneront le nom de l'énumération.

AuthenticationMethod myCurrentSetting = AuthenticationMethod.FORMS;
Console.WriteLine(myCurrentSetting); // Prints: FORMS
string name = Enum.GetNames(typeof(AuthenticationMethod))[(int)myCurrentSetting-1];
Console.WriteLine(name); // Prints: FORMS

Gardez à l’esprit cependant, la deuxième technique suppose que vous utilisez ints et que votre index est basé sur 1 (et non sur 0). La fonction GetNames est également assez lourde en comparaison, vous générez un tableau entier à chaque appel. Comme vous pouvez le voir dans la première technique, .ToString () est en fait appelé implicitement. Ces deux éléments sont déjà mentionnés dans les réponses, bien entendu, j'essaie simplement de clarifier leurs différences.

3
WHol

ancien post mais ...

La réponse à cette question peut en réalité être très simple. Utilisez la fonction Enum.ToString ()

Il y a 6 surcharges de cette fonction, vous pouvez utiliser Enum.Tostring ("F") ou Enum.ToString () pour renvoyer la valeur de chaîne. Pas besoin de s'embêter avec autre chose. Voici un démo de travail

Notez que cette solution peut ne pas fonctionner pour tous les compilateurs ( cette démo ne fonctionne pas comme prév ), mais au moins cela fonctionne pour le dernier compilateur.

3
Hammad Khan

Voici un autre moyen d'accomplir la tâche consistant à associer des chaînes à des énumérations:

struct DATABASE {
    public enum enums {NOTCONNECTED, CONNECTED, ERROR}
    static List<string> strings =
        new List<string>() {"Not Connected", "Connected", "Error"};

    public string GetString(DATABASE.enums value) {
        return strings[(int)value];
    }
}

Cette méthode s'appelle comme ceci:

public FormMain() {
    DATABASE dbEnum;

    string enumName = dbEnum.GetString(DATABASE.enums.NOTCONNECTED);
}

Vous pouvez regrouper les énumérations liées dans leur propre structure. Comme cette méthode utilise le type énumération, vous pouvez utiliser Intellisense pour afficher la liste des énumérations lors de l’appel GetString().

Vous pouvez éventuellement utiliser l'opérateur new sur la structure DATABASE. Si vous ne l'utilisez pas, cela signifie que les chaînes List ne sont pas attribuées avant le premier appel GetString().

3
Russ

basé sur le MSDN: http://msdn.Microsoft.com/en-us/library/cc138362.aspx

foreach (string str in Enum.GetNames(typeof(enumHeaderField)))
{
    Debug.WriteLine(str);
}

str sera le nom des champs

2
junior software

Après avoir lu tout ce qui précède, j’ai le sentiment que les gars ont trop compliqué la question de la transformation des recenseurs en chaînes. J'ai aimé l'idée d'avoir des attributs sur des champs énumérés, mais je pense que ces attributs sont principalement utilisés pour les méta-données, mais dans votre cas, je pense que tout ce dont vous avez besoin est une sorte de localisation.

public enum Color 
{ Red = 1, Green = 2, Blue = 3}


public static EnumUtils 
{
   public static string GetEnumResourceString(object enumValue)
    {
        Type enumType = enumValue.GetType();
        string value = Enum.GetName(enumValue.GetType(), enumValue);
        string resourceKey = String.Format("{0}_{1}", enumType.Name, value);
        string result = Resources.Enums.ResourceManager.GetString(resourceKey);
        if (string.IsNullOrEmpty(result))
        {
            result = String.Format("{0}", value);
        }
        return result;
    }
}

Maintenant, si nous essayons d'appeler la méthode ci-dessus, nous pouvons l'appeler de cette façon

public void Foo()
{
  var col = Color.Red;
  Console.WriteLine (EnumUtils.GetEnumResourceString (col));
}

Il suffit de créer un fichier de ressources contenant toutes les valeurs de l'énumérateur et les chaînes correspondantes.

 Nom de la ressource Valeur de la ressource 
 Color_Red Ma couleur de chaîne en rouge 
 Color_Blue Blueeey 
 Color_Green Hulk Couleur 

Ce qui est en fait très sympa, c’est que ce sera très utile si vous avez besoin que votre application soit localisée, car il vous suffit de créer un autre fichier de ressources avec votre nouvelle langue! et Voe-la!

2
Bormagi

Pour les plus grands ensembles de cordes, les exemples énumérés peuvent devenir fastidieux. Si vous souhaitez une liste de codes d'état ou une liste d'autres énumérations basées sur des chaînes, l'utilisation d'un système d'attributs est gênante et la configuration d'une classe statique avec ses propres instances est gênante. Pour ma propre solution, je me sers de la modélisation T4 pour faciliter la création d’énums à chaîne. Le résultat est similaire à celui de la classe HttpMethod.

Vous pouvez l'utiliser comme ceci:

    string statusCode = ResponseStatusCode.SUCCESS; // Automatically converts to string when needed
    ResponseStatusCode codeByValueOf = ResponseStatusCode.ValueOf(statusCode); // Returns null if not found

    // Implements TypeConverter so you can use it with string conversion methods.
    var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(ResponseStatusCode));
    ResponseStatusCode code = (ResponseStatusCode) converter.ConvertFromInvariantString(statusCode);

    // You can get a full list of the values
    bool canIterateOverValues = ResponseStatusCode.Values.Any(); 

    // Comparisons are by value of the "Name" property. Not by memory pointer location.
    bool implementsByValueEqualsEqualsOperator = "SUCCESS" == ResponseStatusCode.SUCCESS; 

Vous commencez avec un fichier Enum.tt.

<#@ include file="StringEnum.ttinclude" #>


<#+
public static class Configuration
{
    public static readonly string Namespace = "YourName.Space";
    public static readonly string EnumName = "ResponseStatusCode";
    public static readonly bool IncludeComments = true;

    public static readonly object Nodes = new
    {
        SUCCESS = "The response was successful.",
        NON_SUCCESS = "The request was not successful.",
        RESOURCE_IS_DISCONTINUED = "The resource requested has been discontinued and can no longer be accessed."
    };
}
#>

Ensuite, vous ajoutez votre fichier StringEnum.ttinclude.

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ Assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace <#= Configuration.Namespace #>
{
    /// <summary>
    /// TypeConverter implementations allow you to use features like string.ToNullable(T).
    /// </summary>
    public class <#= Configuration.EnumName #>TypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            var casted = value as string;

            if (casted != null)
            {
                var result = <#= Configuration.EnumName #>.ValueOf(casted);
                if (result != null)
                {
                    return result;
                }
            }

            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            var casted = value as <#= Configuration.EnumName #>;
            if (casted != null && destinationType == typeof(string))
            {
                return casted.ToString();
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    [TypeConverter(typeof(<#= Configuration.EnumName #>TypeConverter))]
    public class <#= Configuration.EnumName #> : IEquatable<<#= Configuration.EnumName #>>
    {
//---------------------------------------------------------------------------------------------------
// V A L U E S _ L I S T
//---------------------------------------------------------------------------------------------------
<# Write(Helpers.PrintEnumProperties(Configuration.Nodes)); #>

        private static List<<#= Configuration.EnumName #>> _list { get; set; } = null;
        public static List<<#= Configuration.EnumName #>> ToList()
        {
            if (_list == null)
            {
                _list = typeof(<#= Configuration.EnumName #>).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(<#= Configuration.EnumName #>))
                    .Select(x => x.GetValue(null)).OfType<<#= Configuration.EnumName #>>().ToList();
            }

            return _list;
        }

        public static List<<#= Configuration.EnumName #>> Values()
        {
            return ToList();
        }

        /// <summary>
        /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static <#= Configuration.EnumName #> ValueOf(string key)
        {
            return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
        }


//---------------------------------------------------------------------------------------------------
// I N S T A N C E _ D E F I N I T I O N
//---------------------------------------------------------------------------------------------------      
        public string Name { get; private set; }
        public string Description { get; private set; }
        public override string ToString() { return this.Name; }

        /// <summary>
        /// Implcitly converts to string.
        /// </summary>
        /// <param name="d"></param>
        public static implicit operator string(<#= Configuration.EnumName #> d)
        {
            return d.ToString();
        }

        /// <summary>
        /// Compares based on the == method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares based on the .Equals method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
        {
            return a?.ToString() == b?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            return this.ToString() == o?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(<#= Configuration.EnumName #> other)
        {
            return this.ToString() == other?.ToString();
        }

        /// <summary>
        /// Compares based on the .Name property
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
    }
}

<#+

public static class Helpers
{
        public static string PrintEnumProperties(object nodes)
        {
            string o = "";
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props = nodesTp.GetProperties().OrderBy(p => p.Name).ToArray();

            for(int i = 0; i < props.Length; i++)
            {
                var prop = props[i];
                if (Configuration.IncludeComments)
                {
                    o += "\r\n\r\n";
                    o += "\r\n        ///<summary>";
                    o += "\r\n        /// "+Helpers.PrintPropertyValue(prop, Configuration.Nodes);
                    o += "\r\n        ///</summary>";
                }

                o += "\r\n        public static readonly "+Configuration.EnumName+" "+prop.Name+ " = new "+Configuration.EnumName+"(){ Name = \""+prop.Name+"\", Description = "+Helpers.PrintPropertyValue(prop, Configuration.Nodes)+ "};";
            }

            o += "\r\n\r\n";

            return o;
        }

        private static Dictionary<string, string> GetValuesMap()
        {
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props= nodesTp.GetProperties();
            var dic = new Dictionary<string,string>();
            for(int i = 0; i < props.Length; i++)
            {
                var prop = nodesTp.GetProperties()[i];
                dic[prop.Name] = prop.GetValue(Configuration.Nodes).ToString();
            }
            return dic;
        }

        public static string PrintMasterValuesMap(object nodes)
        {
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props= nodesTp.GetProperties();
            string o = "        private static readonly Dictionary<string, string> ValuesMap = new Dictionary<string, string>()\r\n        {";
            for(int i = 0; i < props.Length; i++)
            {
                var prop = nodesTp.GetProperties()[i];
                o += "\r\n            { \""+prop.Name+"\", "+(Helpers.PrintPropertyValue(prop,Configuration.Nodes)+" },");
            }
            o += ("\r\n        };\r\n");

            return o;
        }


        public static string PrintPropertyValue(PropertyInfo prop, object objInstance)
        {
            switch(prop.PropertyType.ToString()){
                case "System.Double":
                    return prop.GetValue(objInstance).ToString()+"D";
                case "System.Float":
                    return prop.GetValue(objInstance).ToString()+"F";
                case "System.Decimal":
                    return prop.GetValue(objInstance).ToString()+"M";
                case "System.Long":
                    return prop.GetValue(objInstance).ToString()+"L";
                case "System.Boolean":
                case "System.Int16":
                case "System.Int32":
                    return prop.GetValue(objInstance).ToString().ToLowerInvariant();
                case "System.String":
                    return "\""+prop.GetValue(objInstance)+"\"";
            }

            return prop.GetValue(objInstance).ToString();
        }

        public static string _ (int numSpaces)
        {
            string o = "";
            for(int i = 0; i < numSpaces; i++){
                o += " ";
            }

            return o;
        }
}
#>

Enfin, vous recompilez votre fichier Enum.tt et le résultat ressemble à ceci:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Collections.Generic;

namespace YourName.Space
{
    public class ResponseStatusCode
    {
//---------------------------------------------------------------------------------------------------
// V A L U E S _ L I S T 
//---------------------------------------------------------------------------------------------------



        ///<summary>
        /// "The response was successful."
        ///</summary>
        public static readonly ResponseStatusCode SUCCESS = new ResponseStatusCode(){ Name = "SUCCESS", Description = "The response was successful."};


        ///<summary>
        /// "The request was not successful."
        ///</summary>
        public static readonly ResponseStatusCode NON_SUCCESS = new ResponseStatusCode(){ Name = "NON_SUCCESS", Description = "The request was not successful."};


        ///<summary>
        /// "The resource requested has been discontinued and can no longer be accessed."
        ///</summary>
        public static readonly ResponseStatusCode RESOURCE_IS_DISCONTINUED = new ResponseStatusCode(){ Name = "RESOURCE_IS_DISCONTINUED", Description = "The resource requested has been discontinued and can no longer be accessed."};


        private static List<ResponseStatusCode> _list { get; set; } = null;
        public static List<ResponseStatusCode> ToList()
        {
            if (_list == null)
            {
                _list = typeof(ResponseStatusCode).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(ResponseStatusCode))
                    .Select(x => x.GetValue(null)).OfType<ResponseStatusCode>().ToList();
            }

            return _list;
        }

        public static List<ResponseStatusCode> Values()
        {
            return ToList();
        }

        /// <summary>
        /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static ResponseStatusCode ValueOf(string key)
        {
            return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
        }


//---------------------------------------------------------------------------------------------------
// I N S T A N C E _ D E F I N I T I O N 
//---------------------------------------------------------------------------------------------------       
        public string Name { get; set; }
        public string Description { get; set; }
        public override string ToString() { return this.Name; }

        /// <summary>
        /// Implcitly converts to string.
        /// </summary>
        /// <param name="d"></param>
        public static implicit operator string(ResponseStatusCode d)
        {
            return d.ToString();
        }

        /// <summary>
        /// Compares based on the == method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(ResponseStatusCode a, ResponseStatusCode b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares based on the .Equals method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(ResponseStatusCode a, ResponseStatusCode b)
        {
            return a?.ToString() == b?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            return this.ToString() == o?.ToString();
        }

        /// <summary>
        /// Compares based on the .Name property
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
    }
}
1
Pangamma

Quand je suis dans une telle situation, je propose la solution ci-dessous.

Et en tant que classe consommatrice, vous pourriez avoir

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

Et en utilisant un dictionnaire bidirectionnel: Basé sur ceci ( https://stackoverflow.com/a/255638/98616 ) en supposant que les clés seront associées à des valeurs uniques dans le dictionnaire et similaires à (- https://stackoverflow.com/a/255630/98616 ) mais un peu plus élégant. Ce dictionnaire est également énumérable et vous pouvez aller et venir des ints aux chaînes. De plus, vous n'avez pas besoin de chaîne dans votre base de code à l'exception de cette classe.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}
1

Je sais assez bien que cette question a déjà reçu une réponse et que le PO est déjà satisfait de la réponse acceptée. Mais j'ai trouvé que la plupart des réponses, y compris celle acceptée, étaient un peu plus compliquées.

J'ai un projet qui m'a donné une situation comme celle-ci et j'ai pu le réaliser de cette façon.

Tout d'abord, vous devez considérer la casse de vos noms enum:

public enum AuthenticationMethod
{
    Forms = 1,
    WindowsAuthentication = 2,
    SingleSignOn = 3
}

Ensuite, avoir cette extension:

using System.Text.RegularExpression;

public static class AnExtension
{
    public static string Name(this Enum value)
    {
        string strVal = value.ToString();
        try
        {
            return Regex.Replace(strVal, "([a-z])([A-Z])", "$1 $2");
        }
        catch
        {
        }
        return strVal;
    }
}

Grâce à cela, vous pouvez transformer chaque nom d’énumération en représentation de chaîne avec chaque mot séparé par un espace. Ex:

AuthenticationMethod am = AuthenticationMethod.WindowsAuthentication;
MessageBox.Show(am.Name());
0
Abet
Enum.GetName(typeof(MyEnum), (int)MyEnum.FORMS)
Enum.GetName(typeof(MyEnum), (int)MyEnum.WINDOWSAUTHENTICATION)
Enum.GetName(typeof(MyEnum), (int)MyEnum.SINGLESIGNON)

les sorties sont:

"FORMES"

"FENÊTREAUTHENTIFICATION"

"AUTHENTIFICATION UNIQUE"

0
Jahan

Utilisez l'objet Enum.Parse (System.Type enumType, valeur de chaîne, bool ignoreCase); obtenu de http: //blogs.msdn .com/b/tims/archive/2004/04/02/106310.aspx

0
Ricardo Rivaldo

Vous pouvez déclarer enum et le dictionnaire dans lequel la clé sera la valeur de l'énumération. À l'avenir, vous pourrez vous reporter au dictionnaire pour obtenir la valeur. Ainsi, il sera possible de passer des paramètres à des fonctions en tant que type d’énum, ​​mais pour obtenir la valeur réelle du dictionnaire:

using System;
using System.Collections.Generic;

namespace console_test
{
    class Program
    {
        #region SaveFormat
        internal enum SaveFormat
        {
            DOCX,
            PDF
        }

        internal static Dictionary<SaveFormat,string> DictSaveFormat = new Dictionary<SaveFormat, string>
        {
            { SaveFormat.DOCX,"This is value for DOCX enum item" },
            { SaveFormat.PDF,"This is value for PDF enum item" }
        };

        internal static void enum_value_test(SaveFormat save_format)
        {
            Console.WriteLine(DictSaveFormat[save_format]);
        }
        #endregion

        internal static void Main(string[] args)
        {
            enum_value_test(SaveFormat.DOCX);//Output: This is value for DOCX enum item
            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);
        }
    }
}
0
Ramil Shavaleev

Ma réponse, en travaillant sur la réponse de @ user29964 (qui est de loin la plus simple et la plus proche d’un Enum) est

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

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

        public string Value
        {
            get { return _value; }
        }



        public static string GetStringValue(Enum Flagvalue)
        {
            Type type = Flagvalue.GetType();
            string[] flags = Flagvalue.ToString().Split(',').Select(x => x.Trim()).ToArray();
            List<string> values = new List<string>();

            for (int i = 0; i < flags.Length; i++)
            {

                FieldInfo fi = type.GetField(flags[i].ToString());

                StringValue[] attrs =
                   fi.GetCustomAttributes(typeof(StringValue),
                                           false) as StringValue[];
                if (attrs.Length > 0)
                {
                    values.Add(attrs[0].Value);
                }
            }
            return String.Join(",", values);

        }

usage

[Flags]
    public enum CompeteMetric
    {

        /// <summary>
        /// u
        /// </summary>
        [StringValue("u")]//Json mapping
        Basic_UniqueVisitors = 1 //Basic
             ,
        /// <summary>
        /// vi
        /// </summary>
        [StringValue("vi")]//json mapping
        Basic_Visits = 2// Basic
            ,
        /// <summary>
        /// rank
        /// </summary>
        [StringValue("rank")]//json mapping
        Basic_Rank = 4//Basic
 }

Exemple

        CompeteMetric metrics = CompeteMetric.Basic_Visits | CompeteMetric.Basic_Rank;
        string strmetrics = StringValue.GetStringValue(metrics);

cela retournera "vi, rang"

0

Je suis avec Harvey mais n'utilise pas de const. Je peux mélanger et assortir string, int, peu importe.

public class xlsLayout
{
    public int xlHeaderRow = 1;
    public int xlFirstDataRow = 2;
    public int xlSkipLinesBetweenFiles = 1; //so 0 would mean don't skip
    public string xlFileColumn = "A";
    public string xlFieldColumn = "B";
    public string xlFreindlyNameColumn = "C";
    public string xlHelpTextColumn = "D";
}

Puis plus tard ...

public partial class Form1 : Form
{
    xlsLayout xlLayout = new xlsLayout();

    xl.SetCell(xlLayout.xlFileColumn, xlLayout.xlHeaderRow, "File Name");
    xl.SetCell(xlLayout.xlFieldColumn, xlLayout.xlHeaderRow, "Code field name");
    xl.SetCell(xlLayout.xlFreindlyNameColumn, xlLayout.xlHeaderRow, "Freindly name");
    xl.SetCell(xlLayout.xlHelpTextColumn, xlLayout.xlHeaderRow, "Inline Help Text");
}
0
Mike

L’approche que j’ai trouvée pour l’internationalisation d’Enums ou pour obtenir du texte d’Enums à partir de fichiers de ressources respectifs consiste à créer une classe d’attributs en héritant de la classe DescriptionAttribute.

public class EnumResourceAttribute : DescriptionAttribute
{

    public Type ResourceType { get; private set; }
    public string ResourceName { get; private set; }
    public int SortOrder { get; private set; }
    public EnumResourceAttribute(Type ResourceType,
                         string ResourceName,
                         int SortOrder)
    {

        this.ResourceType = ResourceType;
        this.ResourceName = ResourceName;
        this.SortOrder = SortOrder;
    }
}

Créez une autre classe statique qui fournira des méthodes d'extension pour GetString et GetStrings.

public static class EnumHelper
{
    public static string GetString(this Enum value)
    {
        EnumResourceAttribute ea =
       (EnumResourceAttribute)value.GetType().GetField(value.ToString())
        .GetCustomAttributes(typeof(EnumResourceAttribute), false)
         .FirstOrDefault();
        if (ea != null)
        {
            PropertyInfo pi = ea.ResourceType
             .GetProperty(CommonConstants.ResourceManager);
            if (pi != null)
            {
                ResourceManager rm = (ResourceManager)pi
                .GetValue(null, null);
                return rm.GetString(ea.ResourceName);
            }

        }
        return string.Empty;
    }


    public static IList GetStrings(this Type enumType)
    {
        List<string> stringList = new List<string>();
        FieldInfo[] fiArray = enumType.GetFields();
        foreach (FieldInfo fi in fiArray)
        {
            EnumResourceAttribute ea =
                (EnumResourceAttribute)fi
                     .GetCustomAttributes(typeof(EnumResourceAttribute), false)
                     .FirstOrDefault();
            if (ea != null)
            {
                PropertyInfo pi = ea.ResourceType
                                    .GetProperty(CommonConstants.ResourceManager);
                if (pi != null)
                {
                    ResourceManager rm = (ResourceManager)pi
                                          .GetValue(null, null);
                    stringList.Add(rm.GetString(ea.ResourceName));
                }
            }
        }
        return stringList.ToList();
    }
}

Et sur les éléments de votre Enum, vous pouvez écrire:

public enum Priority
{
     [EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh, 1)]
    High,
     [EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberRoutine, 2)]
    Routine
}

Où Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh & Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberRoutine sont des constantes dans le fichier de ressources ou vous pouvez indiquer les chaînes dont les valeurs peuvent être disponibles dans différentes cultures.

Si vous implémentez votre application Web dans une architecture MVC, créez une propriété.

private IList result;
public IList Result
{
    get
    {
        result = typeof(Priority).GetStrings();
        return result;
    }
}

et dans votre fichier .cshtml, vous pouvez simplement lier l’énum à votre liste déroulante comme:

@Html.DropDownListFor(model => Model.vwClinicalInfo.Priority, new SelectList(Model.Result))

Merci Ratnesh

0
Swati