2009-11-17 9 views
6

Estoy escribiendo un método que determina el valor más alto en una enumeración .NET para que pueda crear un BitArray con un bit para cada valor de enumeración:Encontrar el valor más alto en una enumeración

pressedKeys = new BitArray(highestValueInEnum<Keys>()); 

necesito esto en dos enumeraciones diferentes, por lo que la convirtió en un método genérico:

/// <summary>Returns the highest value encountered in an enumeration</summary> 
/// <typeparam name="EnumType"> 
/// Enumeration of which the highest value will be returned 
/// </typeparam> 
/// <returns>The highest value in the enumeration</returns> 
private static int highestValueInEnum<EnumType>() { 
    int[] values = (int[])Enum.GetValues(typeof(EnumType)); 
    int highestValue = values[0]; 
    for(int index = 0; index < values.Length; ++index) { 
    if(values[index] > highestValue) { 
     highestValue = values[index]; 
    } 
    } 

    return highestValue; 
} 

Como se puede ver, estoy echando el valor de retorno de Enum.GetValues ​​() a int [], no EnumType []. Esto se debe a que no puedo convertir EnumType (que es un parámetro de tipo genérico) en int más tarde.

El código funciona. Pero es válido? ¿Siempre puedo convertir el retorno de Enum.GetValues ​​() a int []?

+0

Posible duplicado de [Obteniendo el valor máximo de una enumeración] (https://stackoverflow.com/questions/203377/getting-the-max-value-of-an-enum) – palswim

Respuesta

20

No, no se puede convertir de forma segura a int[]. Los tipos Enum no siempre usan int como valor subyacente. Si se restringe a los tipos enum que hacen tienen un tipo subyacente de int, debería estar bien sin embargo.

Esto se siente como algo que (o I) podría extender Unconstrained Melody para apoyar si quería - de una manera que realmente limitado el tipo de ser un tipo de enumeración en tiempo de compilación, y trabajó para cualquier tipo enumeración, incluso aquellos con bases subyacentes como long y ulong.

Sin melodía no restringida, aún puede hacerlo de una manera general, ya que todos los tipos enum implementan efectivamente el IComparable de manera adecuada. Si está utilizando .NET 3.5 es un trazador de líneas:

private static TEnum GetHighestValue<TEnum>() { 
    return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Max(); 
} 
+0

Jon, ¿por qué la referencia de Microsoft? diga "El tipo subyacente por defecto de los elementos de enumeración es int" si no puedo asignar ningún otro tipo a un valor enum, ni a otros tipos enteros que no sean int32. Intenté asignar 3L a un valor enum y obtuve un error de compilación. –

+0

Gracias por informar la asignación retorcida en el ciclo. Ya lo descubrí yo mismo y me hice ninja una versión corregida en su lugar mientras escribías tu publicación ;-) – Cygon

+2

@ André Pena: El tipo subyacente * predeterminado * es una enumeración, pero puedes declarar una enumeración como "enum Foo" : long "en vez (etc.) Consulte la especificación del lenguaje C# para más detalles. –

0

Fácil! Usando LINQ su bucle puede ser reemplazado con dos líneas de código, o solo una si desea combinarlo todo.

public partial class Form1 : Form 
{ 
    private void Form1_Load(object sender, EventArgs e) 
    { 
     MyEnum z = MyEnum.Second; 
     z++; 
     z++; 

     //see if a specific value is defined in the enum: 
     bool isInTheEnum = !Enum.IsDefined(typeof(MyEnum), z); 

     //get the max value from the enum: 
     List<int> allValues = new List<int>(Enum.GetValues(typeof(MyEnum)).Cast<int>()); 
     int maxValue = allValues.Max(); 
    } 


} 

public enum MyEnum 
{ 
    Zero = 0, 
    First = 1, 
    Second = 2, 
    Third = 3 
} 
+1

¿Por qué molestarse en crear una 'Lista '? No hay necesidad de almacenar todos los valores ... –

+0

Tiene toda la razón, podría haberlo escrito como var max = (desde int x en Enum.GetValues ​​(typeof (MyEnum)).AsQueryable() seleccione x) .Max(); pero ese código no es muy amigable, quería descomponerlo un poco y hacer que el código sea fácil de leer e informativo. Y no creo que "amortiguar los valores" sea menos óptimo que recorrerlos para encontrar el más alto. – slugster

3

De acuerdo con los consejos de Jon Skeet (y gracias también, slugster), este es el código actualizado, ahora usando IComparable porque todavía estoy focalización .NET 2.0.

/// <summary>Returns the highest value encountered in an enumeration</summary> 
/// <typeparam name="EnumType"> 
/// Enumeration of which the highest value will be returned 
/// </typeparam> 
/// <returns>The highest value in the enumeration</returns> 
private static EnumType highestValueInEnum<EnumType>() where EnumType : IComparable { 
    EnumType[] values = (EnumType[])Enum.GetValues(typeof(EnumType)); 
    EnumType highestValue = values[0]; 
    for(int index = 0; index < values.Length; ++index) { 
    if(values[index].CompareTo(highestValue) > 0) { 
     highestValue = values[index]; 
    } 
    } 

    return highestValue; 
} 

Para cualquier persona agarrando el código, es posible que desee agregar una comprobación adicional para que no se explote en las enumeraciones vacías.

+0

Seguramente 'Array.Sort (valores); 'sería mejor que su ciclo? – stevehipwell

+2

Sería más corto, pero ¿por qué ordenar una matriz que voy a tirar cuando termine? Tal vez estoy micro-optimizando aquí, pero Array.Sort() simplemente no me parece intuitivo. – Cygon

Cuestiones relacionadas