2009-11-17 4 views
6

J'écris une méthode qui détermine la valeur la plus élevée dans une énumération .NET je peux créer un BitArray avec un bit pour chaque valeur ENUM:Trouver la valeur la plus élevée dans un Enumeration

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

Je en ai besoin sur deux énumérations différentes, alors je l'ai transformé en une méthode générique:

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

Comme vous pouvez le voir, je couler la valeur de retour de Enum.GetValues ​​() pour int [], pas EnumType []. C'est parce que je ne peux pas convertir EnumType (qui est un paramètre de type générique) en int plus tard.

Le code fonctionne. Mais est-ce valable? Puis-je toujours convertir le retour de Enum.GetValues ​​() en int []?

+0

Possible copie de [Obtenir la valeur maximale d'une énumération] (https://stackoverflow.com/questions/203377/getting-the-max-value-of-an-enum) – palswim

Répondre

20

Non, vous ne pouvez pas diffuser en toute sécurité vers int[]. Les types d'énumération n'utilisent pas toujours int comme valeur sous-jacente. Si vous vous restreignez aux types enum qui font ont un type sous-jacent de int, il devrait être bien cependant.

Cela se sent comme quelque chose que vous (ou I) pourrait se prolonger Unconstrained Melody pour soutenir si vous voulez - d'une manière qui contraint véritablement le type d'être un type ENUM au moment de la compilation, et a travaillé pour tout type enum, même avec des bases sous-jacentes telles que long et ulong. Sans mélodie sans contrainte, vous pouvez toujours le faire d'une manière générale en utilisant le fait que tous les types d'énumération implémentent effectivement IComparable de manière appropriée. Si vous utilisez .NET 3.5, il s'agit d'une seule ligne:

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

Jon, pourquoi la référence Microsoft dire "Le type sous-jacent par défaut des éléments d'énumération est int" si je ne peux pas affecter un autre type à une valeur enum, ni d'autres types entiers autres que int32. J'ai juste essayé d'assigner 3L à une valeur enum et j'ai eu une erreur de compilation. –

+0

Merci d'avoir signalé l'affectation torsadée dans la boucle. Je l'ai déjà découvert moi-même et ninja'd une version corrigée en place pendant que vous deviez écrire votre message ;-) – Cygon

+2

@ André Pena: Le type sous-jacent * par défaut est une énumération, mais vous pouvez déclarer une enum comme "enum Foo". : long "à la place (etc). Voir la spécification du langage C# pour plus de détails. –

0

Easy! En utilisant LINQ, votre boucle peut être remplacée par deux lignes de code, ou une seule si vous voulez tout fusionner.

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

Pourquoi s'embêter à créer une «Liste »? Il n'y a pas besoin de tamponner toutes les valeurs ... –

+0

Vous avez tout à fait raison, j'aurais pu l'écrire comme var max = (de int x dans Enum.GetValues ​​(typeof (MyEnum)).AsQueryable() sélectionne x) .Max(); mais ce n'est pas un morceau de code très sympathique, je voulais le décomposer un peu et rendre le code facile à lire et instructif. Et je ne pense pas que "tamponner les valeurs" soit moins optimal que de les boucler pour trouver le plus haut. – slugster

3

selon les conseils de Jon Skeet (et je vous remercie aussi, slugster), c'est le code mis à jour, en utilisant maintenant IComparable parce que je cible encore .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; 
} 

Pour quiconque saisissant le code, vous pouvez ajouter un contrôle supplémentaire afin qu'il ne gonfle pas sur les énumérations vides.

+0

Sûrement 'Array.Sort (valeurs);' serait mieux que votre boucle? – stevehipwell

+2

Ce serait plus court, mais pourquoi trier un tableau que je vais jeter après que j'ai fini? Peut-être que je suis en train de micro-optimiser ici, mais Array.Sort() ne me semble pas intuitif. – Cygon

Questions connexes