Obtenir la valeur maximale d'une énumération

148

Comment obtenir la valeur maximale d'une énumération?

jdelator
la source
1
Reproduction possible de la recherche de la valeur la plus élevée dans une énumération
Ian Goldpar
1
Je pense que le compilateur pourrait gérer cela, plutôt que d'utiliser un appel Reflection. Une réponse utilisant une méthode de compilation pour cette information recevrait mon vote favorable.
palswim

Réponses:

214

Enum.GetValues ​​() semble renvoyer les valeurs dans l'ordre, vous pouvez donc faire quelque chose comme ceci:

// given this enum:
public enum Foo
{
    Fizz = 3, 
    Bar = 1,
    Bang = 2
}

// this gets Fizz
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Last();

Éditer

Pour ceux qui ne veulent pas lire les commentaires: vous pouvez également le faire de cette façon:

var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Max();

... qui fonctionnera lorsque certaines de vos valeurs d'énumération sont négatives.

Matt Hamilton
la source
3
agréable. tirant parti de: "Les éléments du tableau sont triés par les valeurs binaires des constantes d'énumération." de msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi
2
Je me cognais la tête, pensant que c'était vraiment trival mais une solution élégante a été donnée. Aussi, si vous voulez obtenir la valeur d'énumération, utilisez ensuite Convert.ToInt32 (). Ceci est pour les résultats Google.
jdelator
54
Si vous allez utiliser LINQ, pourquoi ne pas utiliser Max (), qui est beaucoup plus clair et ne se fie pas au "semble-t-il"?
Marc Gravell
3
Il fonctionne mieux, mais seulement si les valeurs de l'énumération ne sont pas négatives, ce qu'elles pourraient être.
ICR
4
Je vote aussi pour Max (). Le dernier () échouerait si enum n'est pas négatif, voir ici
AZ.
42

Je suis d'accord avec la réponse de Matt. Si vous n'avez besoin que de valeurs min et max int, vous pouvez le faire comme suit.

Maximum:

Enum.GetValues(typeof(Foo)).Cast<int>().Max();

Le minimum:

Enum.GetValues(typeof(Foo)).Cast<int>().Min();
Karanvir Kang
la source
21

Selon la réponse de Matt Hamilton, j'ai pensé à créer une méthode d'extension pour cela.

Étant donné que ValueTypen'est pas acceptée comme une contrainte de paramètre de type générique, je ne l' ai pas trouvé une meilleure façon de limiter Tà , Enummais ce qui suit.

Toutes les idées seraient vraiment appréciées.

PS. s'il vous plaît ignorer mon implicite VB, j'aime utiliser VB de cette façon, c'est la force de VB et c'est pourquoi j'aime VB.

Howeva, la voici:

C #:

static void Main(string[] args)
{
    MyEnum x = GetMaxValue<MyEnum>(); //In newer versions of C# (7.3+)
    MyEnum y = GetMaxValueOld<MyEnum>();  
}

public static TEnum GetMaxValue<TEnum>()
  where TEnum : Enum
{
     return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Max();
}

//When C# version is smaller than 7.3, use this:
public static TEnum GetMaxValueOld<TEnum>()
  where TEnum : IComparable, IConvertible, IFormattable
{
    Type type = typeof(TEnum);

    if (!type.IsSubclassOf(typeof(Enum)))
        throw new
            InvalidCastException
                ("Cannot cast '" + type.FullName + "' to System.Enum.");

    return (TEnum)Enum.ToObject(type, Enum.GetValues(type).Cast<int>().Last());
}



enum MyEnum
{
    ValueOne,
    ValueTwo
}

VB:

Public Function GetMaxValue _
    (Of TEnum As {IComparable, IConvertible, IFormattable})() As TEnum

    Dim type = GetType(TEnum)

    If Not type.IsSubclassOf(GetType([Enum])) Then _
        Throw New InvalidCastException _
            ("Cannot cast '" & type.FullName & "' to System.Enum.")

    Return [Enum].ToObject(type, [Enum].GetValues(type) _
                        .Cast(Of Integer).Last)
End Function
Shimmy Weitzhandler
la source
Voir stackoverflow.com/questions/79126/... pour ceci: if (! Type.IsEnum)
Concrete Gannet
vous pouvez également ajouter "struct" à votre where car cela garantira qu'il s'agit d'un ValueType mais ne le limitera pas à Enum C'est ce que j'utilise: where T: struct, IComparable, IFormattable
jdawiz
2
Vous pouvez mettre à jour votre réponse. En C # 7.3, vous pouvez en fait utiliser la méthode d'extension et vous limiter au type Enum (au lieu de struct).
Nordes
Ce n'est cependant pas une méthode d' extension . Mais une bonne méthode utilitaire.
Ray
14

C'est légèrement pointilleux, mais la valeur maximale réelle de tout enumest Int32.MaxValue(en supposant que ce soit un enumdérivé de int). Il est parfaitement légal de jeter toute Int32valeur à un tout , enumpeu importe si oui ou non elle a effectivement déclaré un membre à cette valeur.

Légal:

enum SomeEnum
{
    Fizz = 42
}

public static void SomeFunc()
{
    SomeEnum e = (SomeEnum)5;
}
JaredPar
la source
J'ai eu des cas où la définition d'une variable Integer sur une énumération retournée échoue avec une incompatibilité de type lorsqu'une valeur folle est fournie, il est donc préférable d'utiliser un Long à la place (si vous ne traquez pas correctement l'erreur paresseusement!).
AjV Jsy
9

Après avoir essayé une autre fois, j'ai eu cette méthode d'extension:

public static class EnumExtension
{
    public static int Max(this Enum enumType)
    {           
        return Enum.GetValues(enumType.GetType()).Cast<int>().Max();             
    }
}

class Program
{
    enum enum1 { one, two, second, third };
    enum enum2 { s1 = 10, s2 = 8, s3, s4 };
    enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };

    static void Main(string[] args)
    {
        Console.WriteLine(enum1.one.Max());        
    }
}
Eric Feng
la source
5

L'utilisation de la fonction Dernière n'a pas pu obtenir la valeur maximale. Utilisez la fonction "max" pourrait. Comme:

 class Program
    {
        enum enum1 { one, two, second, third };
        enum enum2 { s1 = 10, s2 = 8, s3, s4 };
        enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };

        static void Main(string[] args)
        {
            TestMaxEnumValue(typeof(enum1));
            TestMaxEnumValue(typeof(enum2));
            TestMaxEnumValue(typeof(enum3));
        }

        static void TestMaxEnumValue(Type enumType)
        {
            Enum.GetValues(enumType).Cast<Int32>().ToList().ForEach(item =>
                Console.WriteLine(item.ToString()));

            int maxValue = Enum.GetValues(enumType).Cast<int>().Max();     
            Console.WriteLine("The max value of {0} is {1}", enumType.Name, maxValue);
        }
    }
Eric Feng
la source
4

En accord avec Matthew J Sullivan, pour C #:

   Enum.GetValues(typeof(MyEnum)).GetUpperBound(0);

Je ne sais vraiment pas pourquoi quelqu'un voudrait utiliser:

   Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last();

... Comme mot pour mot, sémantiquement parlant, cela ne semble pas avoir autant de sens? (toujours bon d'avoir des manières différentes, mais je ne vois pas l'avantage dans ce dernier.)

Ingénieur
la source
4
L'utilisation de GetUpperBound renvoie un nombre (4, pas 40) pour moi: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe
Belle prise, je n'avais pas remarqué ça. OK, donc cette version est idéale pour les énumérations automatiques standard, mais pas pour les énumérations avec des valeurs personnalisées. Je suppose que le gagnant reste M. Hamilton. :)
Ingénieur
GetUpperBound est bon lorsque votre Enum a des valeurs au niveau du bit. (c'est-à-dire - 1, 2, 4, 8, etc.). Par exemple, si vous écriviez un test unitaire, vous voudriez travailler sur une boucle avec autant d'itérations: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX
Quel est le problème avec Length (pour le nombre de valeurs dans l'énumération)? Le plus simple, c'est mieux. (Non pas que cela réponde à la question d'origine.)
Ian Goldby
2

Il existe des méthodes pour obtenir des informations sur les types énumérés sous System.Enum.

Ainsi, dans un projet VB.Net dans Visual Studio, je peux taper «System.Enum». et l'intellisense évoque toutes sortes de bontés.

Une méthode en particulier est System.Enum.GetValues ​​(), qui renvoie un tableau des valeurs énumérées. Une fois que vous avez le tableau, vous devriez être en mesure de faire ce qui convient à votre situation particulière.

Dans mon cas, mes valeurs énumérées ont commencé à zéro et n'ont ignoré aucun nombre, donc pour obtenir la valeur maximale de mon énumération, j'ai juste besoin de savoir combien d'éléments se trouvaient dans le tableau.

Extraits de code VB.Net:

'''''''

Enum MattType
  zerothValue         = 0
  firstValue          = 1
  secondValue         = 2
  thirdValue          = 3
End Enum

'''''''

Dim iMax      As Integer

iMax = System.Enum.GetValues(GetType(MattType)).GetUpperBound(0)

MessageBox.Show(iMax.ToString, "Max MattType Enum Value")

'''''''

la source
Ne fonctionne pas lorsque la matrice présente des espaces. Cela ne fonctionne également que par accident, car l'index d'élément est égal à la valeur stockée à cet index. GetUpperBound()récupère l' index le plus élevé possible dans le tableau renvoyé par GetValues(), et non la valeur la plus élevée stockée dans ce tableau.
JensG
2

En F #, avec une fonction d'assistance pour convertir l'énumération en séquence:

type Foo =
    | Fizz  = 3
    | Bang  = 2

// Helper function to convert enum to a sequence. This is also useful for iterating.
// stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values-c
let ToSeq (a : 'A when 'A : enum<'B>) =
    Enum.GetValues(typeof<'A>).Cast<'B>()

// Get the max of Foo
let FooMax = ToSeq (Foo()) |> Seq.max   

L'exécution ...

> tapez Foo = | Fizz = 3 | Bang = 2
> val ToSeq: 'A -> seq <' B> quand 'A: enum <' B>
> val FooMax: Foo = Fizz

Le when 'A : enum<'B>n'est pas requis par le compilateur pour la définition, mais est requis pour toute utilisation de ToSeq, même par un type enum valide.

Stephen Hosking
la source
1

Il n'est pas utilisable en toutes circonstances, mais je définis souvent moi-même la valeur max:

enum Values {
  one,
  two,
  tree,
  End,
}

for (Values i = 0; i < Values.End; i++) {
  Console.WriteLine(i);
}

var random = new Random();
Console.WriteLine(random.Next((int)Values.End));

Bien sûr, cela ne fonctionnera pas lorsque vous utilisez des valeurs personnalisées dans une énumération, mais cela peut souvent être une solution simple.

yvan vander sanden
la source
1

J'ai utilisé ce qui suit lorsque j'avais besoin des valeurs min et max de mon enum. Je viens de définir un min égal à la valeur la plus basse de l'énumération et un max égal à la valeur la plus élevée de l'énumération en tant que valeurs d'énumération elles-mêmes.

public enum ChannelMessageTypes : byte
{
    Min                 = 0x80, // Or could be: Min = NoteOff
    NoteOff             = 0x80,
    NoteOn              = 0x90,
    PolyKeyPressure     = 0xA0,
    ControlChange       = 0xB0,
    ProgramChange       = 0xC0,
    ChannelAfterTouch   = 0xD0,
    PitchBend           = 0xE0,
    Max                 = 0xE0  // Or could be: Max = PitchBend
}

// I use it like this to check if a ... is a channel message.
if(... >= ChannelMessageTypes.Min || ... <= ChannelMessages.Max)
{
    Console.WriteLine("Channel message received!");
}
XLars
la source