web-dev-qa-db-fra.com

Comment définir une énumération avec une valeur de chaîne?

J'essaie de définir un Enum et d'ajouter des séparateurs communs valides utilisés dans des fichiers CSV ou similaires. Ensuite, je vais le lier à une ComboBox en tant que source de données afin que, chaque fois que j'ajoute ou supprime de la définition Enum, je n'ai besoin de rien modifier dans la liste déroulante.

Le problème est comment puis-je définir enum avec une représentation sous forme de chaîne, quelque chose comme:

public enum SeparatorChars{Comma = ",", Tab = "\t", Space = " "}

71
Saeid Yazdani

Vous ne pouvez pas - les valeurs énumérées doivent être des valeurs intégrales. Vous pouvez utiliser des attributs pour associer une valeur de chaîne à chaque valeur enum ou, dans ce cas, si chaque séparateur est un seul caractère, vous pouvez simplement utiliser la valeur char:

enum Separator
{
    Comma = ',',
    Tab = '\t',
    Space = ' '
}

(EDIT: Juste pour clarifier, vous ne pouvez pas définir char comme type sous-jacent de l’énum, ​​mais vous pouvez utiliser les constantes char pour attribuer la valeur intégrale correspondant à chaque valeur enum. Le type sous-jacent de l’énumération ci-dessus est int.)

Ensuite, une méthode d'extension si vous en avez besoin:

public string ToSeparatorString(this Separator separator)
{
    // TODO: validation
    return ((char) separator).ToString();
}
90
Jon Skeet

Autant que je sache, vous ne serez pas autorisé à attribuer des valeurs de chaîne à enum. Ce que vous pouvez faire est de créer une classe avec des constantes de chaîne.

public static class SeparatorChars
{
    public static String Comma { get { return ",";} } 
    public static String Tab { get { return "\t,";} } 
    public static String Space { get { return " ";} } 
}
66
Maheep

Vous pouvez y arriver, mais cela demandera un peu de travail.

  1. Définissez une classe d'attribut qui contiendra la valeur de chaîne pour enum.
  2. Définissez une méthode d'extension qui renverra la valeur de l'attribut. Par exemple..GetStringValue (cette valeur Enum) retournera la valeur d'attribut.
  3. Ensuite, vous pouvez définir l'enum comme ceci. 
 public enum Test: int {
 [StringValue ("a")] 
 Foo = 1, 
 [StringValue ("b")] 
 Quelque chose = 2 
} 
  1. Pour récupérer la valeur de Attrinbute Test.Foo.GetStringValue ();

Référez-vous: Enum avec les valeurs de chaîne en C #

44
Amit Rai Sharma

Vous ne pouvez pas faire cela avec des enums, mais vous pouvez le faire comme ça:

public static class SeparatorChars
{
    public static string Comma = ",";

    public static string Tab = "\t";

    public static string Space = " ";
}
21
Fischermaen

Pour une simple énumération de valeurs de chaîne (ou de tout autre type):

public static class MyEnumClass
{
    public const string 
        MyValue1 = "My value 1",
        MyValue2 = "My value 2";
}

Utilisation: string MyValue = MyEnumClass.MyValue1;

19
Thierry

Vous ne pouvez pas, car enum ne peut être basé que sur un type numérique primitif . Vous pouvez utiliser un Dictionary à la place:

Dictionary<String, char> separators = new Dictionary<string, char>
{
    {"Comma", ','}, 
    {"Tab",  '\t'}, 
    {"Space", ' '},
};

Vous pouvez également utiliser un Dictionary<Separator, char> ou Dictionary<Separator, string>Separator est une énumération normale:

enum Separator
{
    Comma,
    Tab,
    Space
}

ce qui serait un peu plus agréable que de manipuler les cordes directement.

11
Adam

Une classe qui émule le comportement enum mais en utilisant string au lieu de int peut être créée comme suit ...

public class GrainType
{
    private string _typeKeyWord;

    private GrainType(string typeKeyWord)
    {
        _typeKeyWord = typeKeyWord;
    }

    public override string ToString()
    {
        return _typeKeyWord;
    }

    public static GrainType Wheat = new GrainType("GT_WHEAT");
    public static GrainType Corn = new GrainType("GT_CORN");
    public static GrainType Rice = new GrainType("GT_RICE");
    public static GrainType Barley = new GrainType("GT_BARLEY");

}

Usage...

GrainType myGrain = GrainType.Wheat;

PrintGrainKeyword(myGrain);

puis...

public void PrintGrainKeyword(GrainType grain) 
{
    Console.Writeline("My Grain code is " + grain.ToString());   // Displays "My Grain code is GT_WHEAT"
}
5
colmde

Il est un peu tard pour répondre, mais peut-être que cela aidera quelqu'un à l'avenir. J'ai trouvé plus facile d'utiliser struct pour ce genre de problème. 

L’échantillon suivant est copié en partie à partir du code MS:

namespace System.IdentityModel.Tokens.Jwt
{
    //
    // Summary:
    //     List of registered claims from different sources http://tools.ietf.org/html/rfc7519#section-4
    //     http://openid.net/specs/openid-connect-core-1_0.html#IDToken
    public struct JwtRegisteredClaimNames
    {
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Actort = "actort";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Typ = "typ";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Sub = "sub";
        //
        // Summary:
        //     http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout
        public const string Sid = "sid";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Prn = "prn";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nbf = "nbf";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nonce = "nonce";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string NameId = "nameid";

    }
}
3
suchoss

Bien qu'il ne soit vraiment pas possible d'utiliser une char ou une string comme base pour une énumération, je pense que ce n'est pas ce que vous aimez vraiment faire.

Comme vous l'avez mentionné, vous aimeriez avoir une liste de possibilités et en afficher une représentation sous forme de chaîne dans une liste déroulante. Si l'utilisateur sélectionne l'une de ces représentations sous forme de chaîne, vous souhaitez extraire l'énumération correspondante. Et c'est possible:

Nous devons d'abord lier une chaîne à une valeur enum. Cela peut être fait en utilisant la variable DescriptionAttribute telle qu'elle est décrite ici ou ici .

Vous devez maintenant créer une liste de valeurs enum et les descriptions correspondantes. Cela peut être fait en utilisant la méthode suivante:

/// <summary>
/// Creates an List with all keys and values of a given Enum class
/// </summary>
/// <typeparam name="T">Must be derived from class Enum!</typeparam>
/// <returns>A list of KeyValuePair&lt;Enum, string&gt; with all available
/// names and values of the given Enum.</returns>
public static IList<KeyValuePair<T, string>> ToList<T>() where T : struct
{
    var type = typeof(T);

    if (!type.IsEnum)
    {
        throw new ArgumentException("T must be an enum");
    }

    return (IList<KeyValuePair<T, string>>)
            Enum.GetValues(type)
                .OfType<T>()
                .Select(e =>
                {
                    var asEnum = (Enum)Convert.ChangeType(e, typeof(Enum));
                    return new KeyValuePair<T, string>(e, asEnum.Description());
                })
                .ToArray();
}

Vous aurez maintenant une liste de paires de valeurs de clé de tous les énumérations et leur description. Nous allons donc simplement assigner ceci comme source de données pour une liste déroulante.

var comboBox = new ComboBox();
comboBox.ValueMember = "Key"
comboBox.DisplayMember = "Value";
comboBox.DataSource = EnumUtilities.ToList<Separator>();

comboBox.SelectedIndexChanged += (sender, e) =>
{
    var selectedEnum = (Separator)comboBox.SelectedValue;
    MessageBox.Show(selectedEnum.ToString());
}

L'utilisateur voit toutes les représentations sous forme de chaîne de l'énum et dans votre code, vous obtenez la valeur enum souhaitée.

2
Oliver

Bien, essayez d’abord d’attribuer des chaînes, pas des caractères, même s’ils ne sont qu’un seul caractère. utilisez ',' au lieu de ",". Ensuite, les énumérations ne prennent que des types entiers sans char, vous pouvez utiliser la valeur unicode, mais je vous déconseille vivement de le faire . utiliserait une classe statique avec des chaînes const.

2
dowhilefor

En me basant sur certaines des réponses ici, j'ai implémenté une classe de base réutilisable qui imite le comportement d'un enum mais avec string comme type sous-jacent. Il prend en charge diverses opérations, notamment:

  1. obtenir une liste de valeurs possibles
  2. conversion en chaîne
  3. comparaison avec d'autres instances via .Equals, == et !=
  4. conversion vers/depuis JSON à l'aide d'un JSONConverter JSON.NET

C'est la classe de base dans son intégralité:

public abstract class StringEnumBase<T> : IEquatable<T>
    where T : StringEnumBase<T>
{
    public string Value { get; }

    protected StringEnumBase(string value) => this.Value = value;

    public override string ToString() => this.Value;

    public static List<T> AsList()
    {
        return typeof(T)
            .GetProperties(BindingFlags.Public | BindingFlags.Static)
            .Where(p => p.PropertyType == typeof(T))
            .Select(p => (T)p.GetValue(null))
            .ToList();
    }

    public static T Parse(string value)
    {
        List<T> all = AsList();

        if (!all.Any(a => a.Value == value))
            throw new InvalidOperationException($"\"{value}\" is not a valid value for the type {typeof(T).Name}");

        return all.Single(a => a.Value == value);
    }

    public bool Equals(T other)
    {
        if (other == null) return false;
        return this.Value == other?.Value;
    }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        if (obj is T other) return this.Equals(other);
        return false;
    }

    public override int GetHashCode() => this.Value.GetHashCode();

    public static bool operator ==(StringEnumBase<T> a, StringEnumBase<T> b) => a?.Equals(b) ?? false;

    public static bool operator !=(StringEnumBase<T> a, StringEnumBase<T> b) => !(a?.Equals(b) ?? false);

    public class JsonConverter<T> : Newtonsoft.Json.JsonConverter
        where T : StringEnumBase<T>
    {
        public override bool CanRead => true;

        public override bool CanWrite => true;

        public override bool CanConvert(Type objectType) => ImplementsGeneric(objectType, typeof(StringEnumBase<>));

        private static bool ImplementsGeneric(Type type, Type generic)
        {
            while (type != null)
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == generic)
                    return true;

                type = type.BaseType;
            }

            return false;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken item = JToken.Load(reader);
            string value = item.Value<string>();
            return StringEnumBase<T>.Parse(value);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is StringEnumBase<T> v)
                JToken.FromObject(v.Value).WriteTo(writer);
        }
    }
}

Et voici comment vous implémenteriez votre "string enum":

[JsonConverter(typeof(JsonConverter<Colour>))]
public class Colour : StringEnumBase<Colour>
{
    private Colour(string value) : base(value) { }

    public static Colour Red => new Colour("red");
    public static Colour Green => new Colour("green");
    public static Colour Blue => new Colour("blue");
}

Ce qui pourrait être utilisé comme ceci:

public class Foo
{
    public Colour colour { get; }

    public Foo(Colour colour) => this.colour = colour;

    public bool Bar()
    {
        if (this.colour == Colour.Red || this.colour == Colour.Blue)
            return true;
        else
            return false;
    }
}

J'espère que quelqu'un trouvera cela utile!

2
Ben

Pour les personnes qui arrivent ici et cherchent une réponse à une question plus générique, vous pouvez étendre le concept de classe statique si vous voulez que votre code ressemble à un enum.

L'approche suivante fonctionne lorsque vous n'avez pas finalisé le enum names souhaité et que le enum values est la représentation string du enam name; utilisez nameof() pour simplifier votre refactoring.

public static class Colours
{
    public static string Red => nameof(Red);
    public static string Green => nameof(Green);
    public static string Blue => nameof(Blue);
}

Cela réalise l'intention d'une énumération qui a des valeurs de chaîne (telles que le pseudocode suivant):

public enum Colours
{
    "Red",
    "Green",
    "Blue"
}
1
Zodman

Nous ne pouvons pas définir l'énumération comme type de chaîne. Les types approuvés pour une énumération sont byte, sbyte, short, ushort, int, uint, long ou ulong.

Si vous avez besoin de plus de détails sur le dénombrement, veuillez suivre le lien ci-dessous, ce lien vous aidera à comprendre le dénombrement . Énumération

@ narendras1414

0
Narendra1414

Ça marche pour moi..

   public class ShapeTypes
    {
        private ShapeTypes() { }
        public static string OVAL
        {
            get
            {
                return "ov";
            }
            private set { }
        }

        public static string SQUARE
        {
            get
            {
                return "sq";
            }
            private set { }
        }

        public static string RECTANGLE
        {
            get
            {
                return "rec";
            }
            private set { }
        }
    }
0
Rakesh Kr - Rkh