2010-09-21 4 views
4

Tenez compte des énumérations suivantes:Comment déterminer le type représenté de valeur enum?

enum MyEnum1 { 
    Value1 = 1, 
    Value2 = 2, 
    Value3 = 3 
} 

enum MyEnum2 { 
    Value1 = 'a', 
    Value2 = 'b', 
    Value3 = 'c' 
} 

je peux récupérer la valeur physique représentée par ces valeurs ENUM par coulée explicite, ((int)MyEnum1.Value2) == 2 ou ((char)MyEnum2.Value2) == 'b', mais si je veux obtenir la représentation de char ou la représentation int sans d'abord Connaître le type à lancer?

Est-il possible d'obtenir la valeur sous-jacente d'une énumération sans cast ou est-il au moins possible de déterminer par programme le type correct de la valeur sous-jacente?

Répondre

12

La valeur sous-jacente de ces deux enums est int. Vous utilisez simplement le fait qu'il existe une conversion implicite de char à int dans le second cas.

Par exemple, si vous regardez le deuxième ENUM dans le réflecteur, vous verrez quelque chose comme ceci:

internal enum MyEnum2 
{ 
    Value1 = 0x61, 
    Value2 = 0x62, 
    Value3 = 0x63 
} 

EDIT: Si vous voulez un autre type sous-jacent, vous devez le préciser, par exemple

public enum Foo : long 
{ 
} 

Cependant, seulement byte, sbyte, short, ushort, int, uint, long et ulong sont valides types enum sous-jacents.

+0

C'est la conclusion à laquelle je suis parvenu. Je me suis dit que C# le traitait comme un entier, mais j'avais besoin de quelqu'un pour le confirmer. Merci :) –

+0

@Nathan: J'ai modifié la réponse pour en inclure un peu plus. Fondamentalement, vous ne pouvez pas avoir un type de char sous-jacent. –

1

Et enum est juste un type int dans les coulisses. Vous pouvez le changer en long, en octet et quelques autres, mais ils doivent être des nombres. Char fonctionne juste ici parce que cela peut juste être changé en int. Donc, désolé, je ne pense pas que ce soit possible.

8

Tous les énumérations doivent utiliser l'un des types suivants dans leur déclaration: byte, sbyte, short, ushort, int, uint, long ou ulong. Voici comment vous spécifiez un type:

enum MyEnum3 : long { 
    Value1 = 5L, 
    Value2 = 9L, 
    Value3 = long.MaxValue 
} 

Si vous ne spécifiez pas de type, la valeur par défaut est int.

Malheureusement, vous ne pouvez pas spécifier char comme type sous-jacent. Vous pouvez créer cette « extension » comme un attribut personnalisé:

[AttributeUsage(AttributeTargets.Enum)] 
public class CharAttribute : Attribute { } 

[Char] enum MyEnum2 { 
    Value1 = 'a', 
    Value2 = 'b', 
    Value3 = 'c' 
} 

Et puis une classe comme ceci:

public static class EnumEx { 
    public static Type GetUnderlyingType(Type enumType) { 
    if (!enumType.IsEnum) throw new ArgumentException(); 
    if (enumType.GetCustomAttributes(typeof(CharAttribute), false).Length > 0) { 
     return typeof(char); 
    } 
    return Enum.GetUnderlyingType(enumType); 
    } 
    public static object ConvertToUnderlyingType(object enumValue) { 
    return Convert.ChangeType(enumValue, 
     GetUnderlyingType(enumValue.GetType())); 
    } 
} 

(Soit dit en passant, la méthode Enum.GetUnderlyingType semble être celui que vous recherchez, mais il ne retourne jamais char parce que vous ne pouvez pas avoir ombles énumérations dans la langue)

Cela vous permettra d'accéder à votre extension de la notion de type char énumérations:.

var value3 = EnumEx.ConvertToUnderlyingType(MyEnum2.Value3); 
Console.WriteLine(value3); 

Ceci affichera c sur la console.

Faites attention au type sous-jacent et aux valeurs de vos énumérations char, ils devraient idéalement entrer dans un char pour éviter les échecs de conversion (débordements). Les types de sécurité ont une largeur de 16 bits (exactement comme char) ou moins: byte, sbyte, short ou ushort. D'autres types sont OK si les valeurs de l'énumération peuvent être converties en caractères de 16 bits sans perte de précision (comme dans l'exemple ci-dessus). L'utilisation des littéraux sous-jacents de type et de char sous-jacents (int) en tant que valeurs enum (qui sont implicitement convertibles en int) est suffisant.

MISE À JOUR:

Vous pouvez déclarer char ENUM en F #:

namespace Drawing 

type Color = 
    | Red = 'r' 
    | Green = 'g' 
    | Blue = 'b' 

En C#, vous pouvez l'utiliser comme ceci:

Console.WriteLine(Enum.GetUnderlyingType(typeof(Color))); 

Et il imprimera System.Char .

Mais ... C# se plaindra si vous essayez d'utiliser ses valeurs. Ce:

Console.WriteLine(Color.Red.ToString()); 

donne une erreur du compilateur:

error CS0570: 'Drawing.Color.Red' is not supported by the language

En VB.NET il n'y a pas d'erreur de compilation, mais il y a une erreur d'exécution de Enum.GetName. Il semble que le temps d'exécution n'est pas prêt à traiter avec des enums de char. Voici un extrait de cette méthode (du réflecteur):

if (((!type.IsEnum && (type != intType)) && ((type != typeof(short)) && (type != typeof(ushort)))) && (((type != typeof(byte)) && (type != typeof(sbyte))) && (((type != typeof(uint)) && (type != typeof(long))) && (type != typeof(ulong))))) 
    { 
    throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value"); 
    } 

Il vérifie non seulement que le type est un ENUM, mais il est aussi l'un des types susmentionnés sous-jacents (pour lesquels l'omble est pas une option) . Vous ne devriez donc pas créer de char enums en F #. Vous pouvez utiliser l'approche "extension" que j'ai décrite.

+0

"(Incidemment, la méthode Enum.GetUnderlyingType semble être celle que vous recherchiez, mais elle ne renvoie jamais de caractère parce que vous ne pouvez pas avoir d'énumérations de caractères dans la langue.)" Oui, j'ai testé cela aussi, c'est ce qui mène moi de tirer la conclusion que char comme type de la valeur est vraiment la représentation int32 équivalente d'un char. Tout cet exercice n'était même pas à mes propres fins, mais plutôt de confirmer les conclusions que j'avais déjà tirées en aidant quelqu'un d'autre. Merci pour votre participation! –

+0

Je suis heureux d'avoir pu aider. Que penses-tu de "l'extension" que j'ai proposée? Cela pourrait-il vous aider ou aider votre ami?Ou cela créerait-il seulement plus de problèmes? –

0

Essayez ceci, fonctionne pour moi:

public static bool IsCharEnum(this Type T) 
{ 
    var enumType = T.IsNullableEnum() ? Nullable.GetUnderlyingType(T) : T; 
    if (!enumType.IsEnum) return false; 
    try 
    { 
     return ((int[])Enum.GetValues(enumType)).All(i => char.IsLetter((char)i)); 
    } 
    catch 
    { 
     return false; 
    } 
} 

public static bool IsNullableEnum(this Type T) 
{ 
    var u = Nullable.GetUnderlyingType(T); 
    return (u != null) && u.IsEnum; 
} 

Ajouter ce code à une classe d'extensions, vous pouvez alors l'utiliser comme:

if (propValue.GetType().IsCharEnum()) 
{ 
    propValue = ((char)Convert.ToInt32(propValue)).ToString(); 
} 

Lorsque propValue est de type MyEnum2, la valeur sera changé en char et être 'a', 'b' ou 'c'

+0

Cela ne vous indique pas si l'énumération selon le code source utilise int ou char. Cela vous indique simplement que l'énumération * pourrait être non plus. C'est un code dangereux. –

Questions connexes