2012-01-31 11 views
7

Tengo dificultades para trabajar con algunas enumeraciones heredadas que tienen varios valores cero. Cada vez que llamo al ToString en uno de los valores distintos de cero, se incluyen todos menos el primer valor cero.Obtener nombres de elementos de enumeraciones con valores cero múltiples

¿Hay alguna manera de aislar el nombre de valor distinto de cero sin recurrir a la manipulación o reflexión de cadenas?

//all of the following output "Nada, Zilch, One" 
Console.WriteLine(TestEnum.One); 
Console.WriteLine(Convert.ToString(TestEnum.One)); 
Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum)) 
         .ConvertToString(TestEnum.One)); 

[Flags] 
enum TestEnum 
{ 
    Zero = 0, 
    Nada = 0, 
    Zilch = 0, 
    One = 1 
} 

Editar

entiendo que tiene múltiples elementos con el mismo valor, no se recomienda sin embargo, la enumeración en cuestión se define en un conjunto de legado que no puedo cambiar. De hecho, hay 12 enumeraciones públicas en v4 mscorlib que rompen esta recomendación, según lo determinado por la siguiente consulta LINQ sencilla:

var types = typeof (void).Assembly.GetTypes() 
    .Where(type => type.IsEnum && 
        type.IsPublic && 
        Enum.GetValues(type).Cast<object>() 
         .GroupBy(value => value) 
         .Any(grp => grp.Count() > 1)) 
    .ToList(); 
+1

Es una práctica común que sólo tienen un único valor cero. De hecho, es una práctica común no tener ningún valor repetido. Es una enumeración y existe un peligro inherente que depende del valor de "respaldo". –

+0

¿Puedes mostrar algo del código de cómo se usan estas banderas? ¿Se usan como máscaras de bits? – Maggie

+0

Dado que esto es obviamente un comportamiento no deseado, es posible que desee presentar un informe de error sobre esto: http://connect.microsoft.com. – Heinzi

Respuesta

1

Aquí está uno opción. Funciona, pero es un poco feo. Las variables de valores/nombres no cambiarán, por lo que solo deben calcularse una vez.

suponiendo que tiene una enumeración un poco más complicada, tales como:

[Flags] 
public enum TestEnum 
{ 
    Zero = 0, 
    Nada = 0, 
    Zilch = 0, 
    One = 1, 
    Two = 2, 
    Three = 3, 
    Four = 4 
} 

Aquí hay un código que podría utilizar:

var input = TestEnum.One | TestEnum.Two; 
var values = (TestEnum[]) Enum.GetValues(typeof (TestEnum)); 
var names = Enum.GetNames(typeof (TestEnum)); 
var result = values 
    .Select((value, index) => 
      input == value || (value != 0 && (input & value) == value) 
       ? names[index] 
       : null) 
    .Where(name => name != null); 
var text = string.Join(", ", result); 
Console.WriteLine(text); 
+0

He hecho que tu código LINQ sea más idiomático, espero que no te importe. Me gusta esta solución, pero no funciona para 0 valores. –

+0

Actualizado: ahora funciona para 0 valores. – CodeThug

1

bien, en primer lugar Microsoft recommends against this strongly. Algunas de las palabras más fuertes que he escuchado los utilizan para algo que no hacen cumplir en la compilación: el establecimiento de

Evitar un valor de enumeración banderas a cero, a menos que el valor se utiliza para indicar que todas las banderas se borran. Tal valor debe ser nombrado apropiadamente como se describe en la próxima guía ... Nombre el valor cero de las enumeraciones de banderas Ninguna. Para una enumeración de banderas, el valor siempre debe significar que se borran todas las banderas.

Bien, entonces, ¿por qué sucede esto? De this question tomo es Enum.ToString comporta de forma extraña:

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

EDIT: Puedo reproducir sus resultados, pero no puedo encontrar más documentación sobre por qué comenzaría a imprimir los otros 0 valores. Esperaría que imprimiera NINGUNO de ellos.

¿Puedes simplemente hacer clic con el botón derecho en> refactorizar-> renombrarlos de todos modos y luego eliminar los otros? Parece más fácil y menos en contra de lo que recomienda Microsoft.

+0

Esta es una enumeración de legado definida en un ensamblaje que no puedo cambiar. –

+0

¿Por qué estás en contra de la reflexión? ¿Alguna razón en particular? Esto definitivamente es factible con eso. – DanTheMan

+0

No estoy totalmente en contra, pero preferiría que solo se usara como último recurso. Además, es posible que mi código deba ejecutarse en un entorno de confianza parcial. –

0
Enum.GetValues(typeof (TestEnum)) 

vuelve

{ClassLibrary5.Class1.TestEnum[4]} 
[0] Zilch ClassLibrary5.Class1.TestEnum 
[1] Zilch ClassLibrary5.Class1.TestEnum 
[2] Zilch ClassLibrary5.Class1.TestEnum 
[3] One ClassLibrary5.Class1.TestEnum 

que se van a citar el mismo extracto Dan hizo. ¿Para qué se supone que se utilizarán? ¿Qué necesitas lograr con estas enumeraciones?

0

Asumiendo que tiene una enumeración un poco más compleja, como por ejemplo:

[Flags] 
public enum TestEnum 
{ 
    Zero = 0, 
    Nada = 0, 
    Zilch = 0, 
    One = 1, 
    Two = 2, 
    Four = 4, 
}

podría implementar un método sencillo que devuelve el valor de cadena para que, de esta manera:

public static string TestEnumToString(TestEnum value) 
{ 
    var result = new List(); 

    if (value == TestEnum.Zero) 
    { 
     result.Add("Zero"); 
    } 
    if (value == TestEnum.Nada) 
    { 
     result.Add("Nada"); 
    } 
    if (value == TestEnum.Zilch) 
    { 
     result.Add("Zilch"); 
    } 
    if ((value & TestEnum.One) != 0) 
    { 
     result.Add("One"); 
    } 
    if ((value & TestEnum.Two) != 0) 
    { 
     result.Add("Two"); 
    } 
    if ((value & TestEnum.Four) != 0) 
    { 
     result.Add("Four"); 
    } 

    return string.Join(",", result); 
}
+1

El ejemplo aquí no funcionará porque está marcado como 'banderas'. Si tengo 0x03 como mi valor, pero solo un 0x01 y 0x02 en mi enumeración, arrojaré la AgumentException. – DanTheMan

+0

Código actualizado para tener en cuenta el atributo Flags. Por favor revise. – CodeThug

+0

Esta solución crea una carga de mantenimiento para futuros desarrolladores. Prefiero tu otra sugerencia. –

Cuestiones relacionadas