2009-11-17 23 views
6

Sto scrivendo un metodo che determina il valore più alto in un'enumerazione .NET in modo da poter creare un BitArray con un bit per ogni valore enum:Trovare il valore più alto in un'enumerazione

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

Ho bisogno di questo su due enumerazioni differenti, così ho girato in un metodo generico:

/// <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; 
} 

Come potete vedere, sto gettando il valore di ritorno di Enum.GetValues ​​() per int [], non EnumType []. Questo perché non posso eseguire il cast di EnumType (che è un parametro di tipo generico) su int successivamente.

Il codice funziona. Ma è valido? Posso sempre trasmettere il ritorno da Enum.GetValues ​​() a int []?

+0

Possibile duplicato di [Ottenere il valore massimo di un enum] (https://stackoverflow.com/questions/203377/getting-the-max-value-of-an-enum) – palswim

risposta

20

No, non è possibile trasmettere in modo sicuro a int[]. I tipi Enum non utilizzano sempre int come valore sottostante. Se ti limiti ai tipi enum che fanno hanno un tipo sottostante di int, dovrebbe comunque andare bene.

Questo si sente come qualcosa che (o io) potrebbe estendersi Unconstrained Melody per sostenere se si voleva - in un modo che realmente vincolato al tipo di essere un tipo enum in fase di compilazione, e ha lavorato per qualsiasi tipo enum, anche quelli con basi sottostanti come long e ulong.

Senza melodia non vincolata, è comunque possibile farlo in modo generale utilizzando il fatto che tutti i tipi di enumerazione implementano in modo efficace IComparable in modo appropriato. Se si utilizza .NET 3.5 è un one-liner:

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

Jon, perché fa riferimento a Microsoft dì "Il tipo di base predefinito degli elementi di enumerazione è int" se non riesco ad assegnare nessun altro tipo a un valore enum, né altri tipi di interi diversi da int32. Ho appena provato ad assegnare 3L a un valore enum e ho ottenuto un errore di compilazione. –

+0

Grazie per aver segnalato l'assegnazione distorta nel ciclo. L'ho già scoperto io stesso e ho inserito una versione corretta mentre dovevi scrivere il tuo post ;-) – Cygon

+2

@ André Pena: Il tipo predefinito * di default è un enum, ma puoi dichiarare un enum come "enum Foo" : long "invece (ecc.). Vedi le specifiche del linguaggio C# per maggiori dettagli. –

0

Facile! Usando LINQ il tuo loop può essere sostituito con due linee di codice, o solo uno se vuoi mescolarlo tutto insieme.

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

Perché preoccuparsi di creare un 'Elenco ' comunque? Non c'è bisogno di bufferizzare tutti i valori ... –

+0

Hai perfettamente ragione, potrei averlo appena scritto come var max = (da int x in Enum.GetValues ​​(typeof (MyEnum)).AsQueryable() seleziona x) .Max(); ma non è un pezzo di codice dall'aspetto molto amichevole, volevo scomporlo un po 'e rendere il codice facile da leggere e informativo. E non penso che il "buffering dei valori" sia meno ottimale di un ciclo su di essi per trovare il massimo. – slugster

3

Secondo il consiglio di Jon Skeet (e grazie anche, slugster), questo è il codice aggiornato, ora utilizzando IComparable perché sto ancora mira 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; 
} 

Per chiunque afferrare il codice, si potrebbe desiderare di aggiungere un ulteriore controllo in modo da non saltare in aria su enumerazioni vuote.

+0

Sicuramente 'Array.Sort (valori);' sarebbe meglio del loop? – stevehipwell

+2

Sarebbe più breve, ma perché ordinare una matrice che ho intenzione di gettare dopo che ho finito? Forse sto microtaggiando qui, ma Array.Sort() semplicemente non mi sembra intuitivo. – Cygon

Problemi correlati