58 votes

Quelle constante Enum vais-je obtenir si les valeurs Enum sont identiques?

Est-il logique de la constante-je obtenir si il y a plus d'un enum constante qui a la même valeur?

J'ai essayé les variations ci-dessous, mais n'a pas pu obtenir un raisonnable, logique.

La Méthode Main:

public class Program
{
    public static void Main(string[] args)
    {
        Test a = 0;
        Console.WriteLine(a);
    }
}

Premier essai:

enum Test
{
    a1=0,
    a2=0,
    a3=0,
    a4=0,
}

Sortie:

a2

Deuxième essai:

enum Test
{
    a1=0,
    a2=0,
    a3,
    a4=0,
}

Sortie:

a4

Troisième essai:

enum Test
{
    a1=0,
    a2=0,
    a3,
    a4,
}

Sortie:

a2

Quatrième essai:

enum Test
{
    a1=0,
    a2=0,
    a3,
    a4
}

Sortie:

a1

68voto

D Stanley Points 54768

La documentation effectivement adresses ceci:

Si plusieurs membres de l'énumération ont la même valeur sous-jacente et que vous tentez de récupérer la chaîne de la représentation d'une énumération du nom du membre, fondé sur sa valeur sous-jacente, votre code ne doit pas faire d'hypothèses sur le nom de la méthode sera de retour.

(emphase ajoutée)

Toutefois, cela ne signifie pas que le résultat est aléatoire. Ce qui signifie que c'est un détail d'implémentation qui est sujet à changement. La mise en œuvre pourrait changer complètement avec juste un patch, peut être différente entre compilateurs (MONO, Roslyn, etc.), et être différents sur les différentes plates-formes.

Si votre système est conçu de manière qu'il exige que la recherche inversée pour les enums est cohérente dans le temps et plates-formes, puis ne pas utiliser Enum.ToString. Soit changer votre conception de sorte qu'il ne dépend pas que de détail, ou écrire votre propre méthode qui va être cohérente.

Donc, vous ne devriez pas écrire du code qui dépend de la mise en œuvre, ou vous prenez un risque que cela va changer à votre insu dans une version future.

28voto

Xiaoy312 Points 10304

TL;DR: Tous les champs d'un enum sera extrait par la réflexion, puis l'insertion triée et binaire fouillé pour la première valeur correspondante.


L'appel de la chaîne d'regardé ce :

Enum.Tostring();
Enum.InternalFormat(RuntimeType eT, Object value);
Enum.GetName(Type enumType, Object value);
Type.GetEnumName(object value);

Type.GetEnumName(object value) est mis en œuvre en tant que telle :

    public virtual string GetEnumName(object value)
    {
        // standard argument guards...

        Array values = GetEnumRawConstantValues();
        int index = BinarySearch(values, value);

        if (index >= 0)
        {
            string[] names = GetEnumNames();
            return names[index];
        }

        return null;
    }

Les deux GetEnumRawConstantValues() et GetEnumNames() dépendent GetEnumData(out string[] enumNames, out Array enumValues) :

    private void GetEnumData(out string[] enumNames, out Array enumValues)
    {
        Contract.Ensures(Contract.ValueAtReturn<String[]>(out enumNames) != null);
        Contract.Ensures(Contract.ValueAtReturn<Array>(out enumValues) != null);

        FieldInfo[] flds = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

        object[] values = new object[flds.Length];
        string[] names = new string[flds.Length];

        for (int i = 0; i < flds.Length; i++)
        {
            names[i] = flds[i].Name;
            values[i] = flds[i].GetRawConstantValue();
        }

        // Insertion Sort these values in ascending order.
        // We use this O(n^2) algorithm, but it turns out that most of the time the elements are already in sorted order and
        // the common case performance will be faster than quick sorting this.
        IComparer comparer = Comparer.Default;
        for (int i = 1; i < values.Length; i++)
        {
            int j = i;
            string tempStr = names[i];
            object val = values[i];
            bool exchanged = false;

            // Since the elements are sorted we only need to do one comparision, we keep the check for j inside the loop.
            while (comparer.Compare(values[j - 1], val) > 0)
            {
                names[j] = names[j - 1];
                values[j] = values[j - 1];
                j--;
                exchanged = true;
                if (j == 0)
                    break;
            }

            if (exchanged)
            {
                names[j] = tempStr;
                values[j] = val;
            }
        }

        enumNames = names;
        enumValues = values;
    }

Lorsqu'il est suivi, GetFields(BindingFlags bindingAttr) conduit à une abstract méthode, mais la recherche "GetFields" sur msdn va vous céder EnumBuilder.GetFields(BindingFlags bindingAttr). Et si nous suivons sa chaîne d'appel :

EnumBuilder.GetFields(BindingFlags bindingAttr);
TypeBuilder.GetFields(BindingFlags bindingAttr);
RuntimeType.GetFields(BindingFlags bindingAttr);
RuntimeType.GetFieldCandidates(String name, BindingFlags bindingAttr, bool allowPrefixLookup);
RuntimeTypeCache.GetFieldList(MemberListType listType, string name);
RuntimeTypeCache.GetMemberList<RuntimeFieldInfo>(ref MemberInfoCache<T> m_cache, MemberListType listType, string name, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.GetMemberList(MemberListType listType, string name, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.Populate(string name, MemberListType listType, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.GetListByName(char* pName, int cNameLen, byte* pUtf8Name, int cUtf8Name, MemberListType listType, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.PopulateFields(Filter filter);
// and from here, it is a wild ride...

Donc, je vais citer Type.GetFields remarques :

Le GetFields méthode ne retourne pas de champs dans un ordre particulier, comme l'ordre alphabétique ou par ordre de déclaration. Votre code ne doit pas dépendre de l'ordre dans lequel les champs sont retournés, parce que cet ordre varie.

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