27 votes

C # Obtention des valeurs Enum

J'ai une énumération contenant les éléments suivants (par exemple):

  • Royaume-Uni,
  • États Unis,
  • France,
  • le Portugal

Dans mon code, j'utilise Country.UnitedKingdom mais je veux que la valeur soit UK si je l'affecte à une chaîne par exemple.

Est-ce possible?

51voto

Jon Skeet Points 692016

Vous ne pouvez pas affecter une valeur d'enum à une chaîne de commencer avec. Vous devez appeler ToString(), ce qui permettrait de convertir Country.UnitedKingdom de "royaume-uni".

Deux options se dégagent:

  • Créer un Dictionary<Country, string>
  • Une instruction switch
  • Décorer chaque valeur à un attribut, et de la charge qu'avec réflexion

Commentaires à propos de chacun d'eux...

Exemple de code pour l' Dictionary<Country,string>

using System;
using System.Collections.Generic;

enum Country
{
    UnitedKingdom, 
    UnitedStates,
    France,
    Portugal
}

class Test
{
    static readonly Dictionary<Country, string> CountryNames =
        new Dictionary<Country, string>
    {
        { Country.UnitedKingdom, "UK" },
        { Country.UnitedStates, "US" },
    };

    static string ConvertCountry(Country country) 
    {
        string name;
        return (CountryNames.TryGetValue(country, out name))
            ? name : country.ToString();
    }

    static void Main()
    {
        Console.WriteLine(ConvertCountry(Country.UnitedKingdom));
        Console.WriteLine(ConvertCountry(Country.UnitedStates));
        Console.WriteLine(ConvertCountry(Country.France));
    }
}

Vous pourriez mettre la logique de l' ConvertCountry dans une méthode d'extension. Par exemple:

// Put this in a non-nested static class
public static string ToBriefName(this Country country) 
{
    string name;
    return (CountryNames.TryGetValue(country, out name))
        ? name : country.ToString();
}

Ensuite, vous pouvez écrire:

string x = Country.UnitedKingdom.ToBriefName();

Comme mentionné dans les commentaires, le dictionnaire par défaut comparer impliquera de boxe, qui est non-idéal. Pour un one-off, je voudrais vivre avec ça jusqu'à ce que j'ai trouvé que c'était un goulot d'étranglement. Si je faisais cela pour de multiples enums, allais-je écrire une classe réutilisable.

Instruction Switch

Je suis d'accord avec yshuditelu de répondre, en suggérant à l'aide d'un switch déclaration pour les cas relativement rares. Cependant, chaque cas est une seule déclaration, je serais personnellement changer mon style de codage de cette situation, pour avoir un code compact, mais lisible:

public static string ToBriefName(this Country country) 
{
    switch (country)
    {
        case Country.UnitedKingdom:  return "UK";
        case Country.UnitedStates:   return "US";
        default:                     return country.ToString();
    }
}

Vous pouvez ajouter plus de cas de ce sans faire de trop grands, et il est facile de jeter les yeux en face de la valeur d'énumération à la valeur de retour.

DescriptionAttribute

Le point de Rado fait sur le code pour DescriptionAttribute il est réutilisable est une bonne idée, mais dans ce cas, je vous recommande contre l'utilisation de la réflexion à chaque fois que vous avez besoin pour obtenir une valeur. J'écrirais probablement un générique classe statique pour tenir une table de recherche (probablement un Dictionary, éventuellement avec un comparateur comme mentionné dans les commentaires). Les méthodes d'Extension ne peuvent pas être définies dans des classes génériques, de sorte que vous auriez probablement quelque chose comme:

public static class EnumExtensions
{
    public static string ToDescription<T>(this T value) where T : struct
    {
        return DescriptionLookup<T>.GetDescription(value);
    }

    private static class DescriptionLookup<T> where T : struct
    {
        static readonly Dictionary<T, string> Descriptions;

        static DescriptionLookup()
        {
            // Initialize Descriptions here, and probably check
            // that T is an enum
        }

 

22voto

Scott Ivey Points 19577

Je préfère utiliser l'attribut Description sur mes énumérations. Ensuite, vous pouvez utiliser le code suivant pour récupérer cette description de l'énumération.

 enum MyCountryEnum
{    
    [Description("UK")]
    UnitedKingdom = 0,    

    [Description("US")]
    UnitedStates = 1,    

    [Description("FR")]
    France = 2,    

    [Description("PO")]
    Portugal = 3
}

public static string GetDescription(this Enum value)
{
    var type = value.GetType();

    var fi = type.GetField(value.ToString());

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

    return descriptions.Length > 0 ? descriptions[0].Description : value.ToString();
}

public static SortedDictionary<string, T> GetBoundEnum<T>() where T : struct, IConvertible
{
    // validate.
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("T must be an Enum type.");
    }

    var results = new SortedDictionary<string, T>();

    FieldInfo[] fieldInfos = typeof(T).GetFields();

    foreach (var fi in fieldInfos)
    {

        var value = (T)fi.GetValue(fi);
        var description = GetDescription((Enum)fi.GetValue(fi));

        if (!results.ContainsKey(description))
        {
            results.Add(description, value);
        }
    }
}
 

Et puis pour obtenir ma liste d'énumérations liées, c'est simplement un appel à

 GetBoundEnum<MyCountryEnum>()
 

Pour obtenir la description d'une seule énumération, il vous suffit d'utiliser la méthode d'extension comme celle-ci

 string whatever = MyCountryEnum.UnitedKingdom.GetDescription();
 

15voto

Timothy Carter Points 7079

Vous pouvez créer une méthode d'extension public static string ToShortString(this Country country) . Dans la méthode, vous pouvez utiliser un dictionnaire statique comme le suggère Jon, ou vous pouvez simplement faire un commutateur.

Exemple:

 public static class CountryExtensions
{
    public static string ToShortString( this Country target )
    {
    	switch (target) {
    		case Country.UnitedKingdom:
    			return "UK";
    		case Country.UnitedStates:
    			return "US";
    		case Country.France:
    			return "FR";
    		case Country.Portugal:
    			return "PT";
    		default:
    			return "None";
    	}
    }
}
 

6voto

rein Points 15639

Pseudo code:

 enum MyCountryEnum
{
    UnitedKingdom = 0,
    UnitedStates = 1,
    France = 2,
    Portugal = 3,
}

string[] shortCodes = new string[] {"UK", "US", "FR", "PO"};


MyCountryEnum enumValue = MyCountryEnum.UnitedKingdom;
string code = shortCodes[enumValue];
 

3voto

Timothy Carter Points 7079

Une autre possibilité qui n'a pas été mentionné, c'est quelque chose comme ceci:

public class Country
{
    public static readonly Country UnitedKingdom = new Country("UK");
    public static readonly Country UnitedStates = new Country("US");
    public static readonly Country France = new Country("FR");
    public static readonly Country Protugal = new Country("PT");

    private Country(string shortName)
    {
        ShortName = shortName;
    }

    public string ShortName { get; private set; }
}

À partir de ce point, vous auriez pu ajouter plus de propriétés, mais méfiez-vous de la façon dont beaucoup vous l'ajouter à la classe, et la façon dont beaucoup de membres statiques que vous ajoutez, que la mémoire de ballonnements, il ajoute pourrait rendre pas la peine.

Je ne pense pas qu'il existe de nombreux cas où cette stratégie est la meilleure approche, mais c'est une option à considérer lorsque vous tentez d'ajouter des propriétés ou attributs à quelque chose que vous voulez être en mesure de traiter essentiellement comme un enum.

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