2011-01-04 15 views
8

Hola chicos, he estado teniendo problemas con el "orden" de los valores de una enumeración. Es un poco difícil de explicar, es por eso que escribí algo de código:¿Por qué (y cómo) influye el orden de un Enum en el valor de ToString?

class Program 
{ 
    public enum EnumA 
    { 
     One = 1, 
     Two = One, 
     Three = Two, 
     Four = 4 
    } 

    public enum EnumB 
    { 
     One = 1, 
     Two = One, 
     Four = 4, 
     Three = Two 
    } 

    public enum EnumC 
    { 
     Two = One, 
     Three = Two, 
     Four = 4, 
     One = 1 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Enum A:"); 
     Console.WriteLine(EnumA.One); 
     Console.WriteLine(EnumA.Two); 
     Console.WriteLine(EnumA.Three); 
     Console.WriteLine(EnumA.Four); 
     Console.WriteLine(); 

     Console.WriteLine("Enum B:"); 
     Console.WriteLine(EnumB.One); 
     Console.WriteLine(EnumB.Two); 
     Console.WriteLine(EnumB.Three); 
     Console.WriteLine(EnumB.Four); 
     Console.WriteLine(); 

     Console.WriteLine("Enum C:"); 
     Console.WriteLine(EnumC.One); 
     Console.WriteLine(EnumC.Two); 
     Console.WriteLine(EnumC.Three); 
     Console.WriteLine(EnumC.Four); 
     Console.WriteLine(); 

     Console.ReadLine(); 
    } 
} 

La salida es:

Enum A: Dos Dos Dos Cuatro

Enum B: Tres Tres Tres Cuatro

Enum C:Una Una Una Cuatro

Mi pregunta es: ¿Por qué !? No puedo encontrar la lógica para la salida. La mayoría de las veces hay algo de lógica que encontrar, así que espero que ustedes puedan arrojar algo de luz sobre este tema.

Utilicé VS2010/.Net 4.0 para compilar y ejecutar el código.

Respuesta

12

El comportamiento se especifica como "indefinido" (pensé que había un patrón vi hace un momento, pero al parecer no.) El documentation llama explícitamente a esto:

Si varios miembros de la enumeración tienen el mismo valor subyacente e intenta recuperar la representación de cadena del nombre de un miembro de enumeración en función de su valor subyacente, su código no debe hacer suposiciones sobre qué nombre devolverá el método.

O bien, haga que sus valores enum sean distintos o cree explícitamente un mapa del valor al nombre deseado.

+0

Hola Jon, pensé lo mismo, pero ... en el caso de EnumA debería ser tres y no dos. Incluso si cambio el valor Tres = Uno, el EnumA.Three.ToString() sigue siendo "Dos". –

+0

Ya veo ... ¡qué raro! Encontré el problema usando una enumeración con formatos de archivo y cosas así. Aún así ... es raro, ¿no? –

+0

@Kees: No creo que sea particularmente extraño, es como si las tablas hash no estuvieran ordenadas. (De hecho, se puede basar exactamente en eso :) –

5

El primero que hay que observar, si descompilación dentro IL, es que las llamadas a WriteLine todos se parecen notablemente similares:

L_000c: ldc.i4.1 
    L_000d: box ConsoleApplication2.Program/EnumA 
    L_0012: call void [mscorlib]System.Console::WriteLine(object) 
    L_0017: nop 
    L_0018: ldc.i4.1 
    L_0019: box ConsoleApplication2.Program/EnumA 
    L_001e: call void [mscorlib]System.Console::WriteLine(object) 
    L_0023: nop 
    L_0024: ldc.i4.1 
    L_0025: box ConsoleApplication2.Program/EnumA 
    L_002a: call void [mscorlib]System.Console::WriteLine(object) 
    L_002f: nop 
    L_0030: ldc.i4.4 
    L_0031: box ConsoleApplication2.Program/EnumA 
    L_0036: call void [mscorlib]System.Console::WriteLine(object) 
    L_003b: nop 
    L_003c: call void [mscorlib]System.Console::WriteLine() 
    L_0041: nop 

Es decir, la carga de estos valores de enumeración está cargando el valor "1" tres veces, y luego llamar al WriteLine. Por lo tanto, no debería sorprendernos que el 1er 3 llame a todos los resultados en el mismo valor de.

He intentado algunos experimentos, pero no puedo señalar ningún comportamiento particular (no documentado) en el que pueda confiar para predecir qué valor se imprimirá.

+0

No estoy tan interesado en MSIL: P, pero parece que los primeros valores apuntan a lo mismo: ldc.i4.1. Me pregunto cuáles serían los valores de ldc.i4.2, ldc.i4.3 ... –

+0

@Kees - yup, el ldc.i4.1 dice "carga el valor constante inmediato 1 en la pila". Ese es el valor de EnumA.One, pero también es el valor de EnumA.Two y EnumA.Three, es decir, en este momento de la compilación, los nombres enum han desaparecido por completo, y estamos trabajando con los valores numéricos por completo. –

+0

Entonces, básicamente, podemos concluir que el "valor real" es 1 ... pero no es posible que .Net determine el valor de la cadena (como se especifica en la documentación). (Editar: uno -> 1) –

Cuestiones relacionadas