Ottenere il valore massimo di un enum


148

Come si ottiene il valore massimo di un enum?



1
Penserei che il compilatore potesse gestirlo, piuttosto che usare una chiamata Reflection. Una risposta che utilizzava un metodo di compilazione per queste informazioni avrebbe ricevuto il mio voto positivo.
palswim,

Risposte:


214

Enum.GetValues ​​() sembra restituire i valori in ordine, quindi puoi fare qualcosa del genere:

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

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

modificare

Per coloro che non sono disposti a leggere i commenti: puoi anche farlo in questo modo:

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

... che funzionerà quando alcuni dei tuoi valori enum sono negativi.


3
simpatico. sfruttando: "Gli elementi dell'array sono ordinati in base ai valori binari delle costanti di enumerazione." da msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi

2
Schioccavo la testa, pensando che fosse davvero trivalente, ma fu data una soluzione elegante. Inoltre, se si desidera ottenere il valore enum, utilizzare Convert.ToInt32 () in seguito. Questo è per i risultati di Google.
jdelator,

54
Se hai intenzione di utilizzare LINQ, perché non usare Max (), che è molto più chiaro e non si basa su "sembra"?
Marc Gravell

3
Si comporta meglio, ma solo se i valori dell'enum non sono negativi, come potrebbero essere.
ICR

4
Voto anche per Max (). L'ultimo () fallirebbe se l'enum non fosse negativo, vedi qui
AZ.

42

Sono d'accordo con la risposta di Matt. Se hai bisogno solo di valori min e max int, puoi farlo come segue.

Massimo:

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

Minimo:

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

21

Secondo la risposta di Matt Hamilton, ho pensato di creare un metodo di estensione per questo.

Dal momento che ValueTypenon è accettato come vincolo di parametro di tipo generico, non ho trovato un modo migliore per limitarmi Ta Enumquanto segue.

Qualsiasi idea sarebbe davvero apprezzata.

PS. per favore ignora la mia implicazione VB, adoro usare VB in questo modo, questa è la forza di VB ed è per questo che adoro VB.

Howeva, eccolo qui:

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

Vedi stackoverflow.com/questions/79126/… per questo: if (! Type.IsEnum)
Concrete Gannet

puoi anche aggiungere "struct" al tuo dove questo assicurerà che sia un ValueType ma non limitarlo a Enum Questo è quello che uso: where T: struct, IComparable, IFormattable
jdawiz

2
Potresti aggiornare la tua risposta. In C # 7.3 potresti effettivamente fare il metodo di estensione e anche limitarti al tipo Enum (invece di struct).
Nordes,

Questo non è un metodo di estensione però. Ma un buon metodo di utilità.
Ray

14

Questo è leggermente nitido ma il valore massimo effettivo di qualsiasi enumè Int32.MaxValue(supponendo che sia enumderivato da int). È perfettamente legale assegnare qualsiasi Int32valore a uno enumindipendentemente dal fatto che abbia effettivamente dichiarato un membro con quel valore.

Legale:

enum SomeEnum
{
    Fizz = 42
}

public static void SomeFunc()
{
    SomeEnum e = (SomeEnum)5;
}

Ho avuto casi in cui l'impostazione di una variabile Integer su un enum restituito fallisce con la mancata corrispondenza del tipo quando viene fornito un valore folle, quindi è meglio usare un Long invece (se pigramente non intrappoli correttamente l'errore!).
AjV Jsy

9

Dopo aver provato un'altra volta, ho ottenuto questo metodo di estensione:

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());        
    }
}

5

Utilizzare l'ultima funzione non è stato in grado di ottenere il valore massimo. Utilizzare la funzione "max" potrebbe. Piace:

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

4

In accordo con Matthew J Sullivan, per C #:

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

Non sono davvero sicuro del motivo per cui qualcuno vorrebbe usare:

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

... Come parola per parola, semanticamente parlando, non sembra avere molto senso? (sempre bello avere modi diversi, ma non vedo il vantaggio in quest'ultimo.)


4
L'uso di GetUpperBound restituisce un conteggio (4, non 40) per me: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe

Bella cattura, non me ne ero accorto. OK, quindi questa versione è ottima per gli enumeratori automatici standard, ma non per quelli con valori personalizzati. Immagino che il vincitore rimanga Mr Hamilton. :)
Ingegnere

GetUpperBound è utile quando Enum ha valori bit per bit. (ovvero - 1, 2, 4, 8, ecc.). Ad esempio, se stavi scrivendo un unit test, ti piacerebbe lavorare attraverso un ciclo con così tante iterazioni: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX,

Cosa c'è di sbagliato in Lunghezza (per il numero di valori nell'enum)? Più semplice è meglio. (Non che questo risponda alla domanda originale.)
Ian Goldby,

2

Esistono metodi per ottenere informazioni sui tipi enumerati in System.Enum.

Quindi, in un progetto VB.Net in Visual Studio posso digitare "System.Enum". e l'intellisenso fa emergere ogni sorta di bontà.

Un metodo in particolare è System.Enum.GetValues ​​(), che restituisce una matrice dei valori enumerati. Una volta che hai l'array, dovresti essere in grado di fare tutto ciò che è appropriato per le tue circostanze particolari.

Nel mio caso, i miei valori enumerati sono partiti da zero e non sono stati saltati numeri, quindi per ottenere il valore massimo per il mio enum ho solo bisogno di sapere quanti elementi c'erano nell'array.

Frammenti di codice 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")

'''''''

Non funziona quando l'array presenta delle lacune. Funziona anche solo per caso, perché l'indice degli elementi è uguale al valore memorizzato in quell'indice. GetUpperBound()recupera l' indice più alto possibile nell'array restituito da GetValues(), non il valore più alto memorizzato all'interno dell'array.
JensG,

2

In F #, con una funzione di aiuto per convertire l'enum in una sequenza:

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   

Eseguendolo ...

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

Non when 'A : enum<'B>è richiesto dal compilatore per la definizione, ma è richiesto per qualsiasi uso di ToSeq, anche per un tipo enum valido.


1

Non è utilizzabile in tutte le circostanze, ma spesso definisco personalmente il valore massimo:

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));

Ovviamente questo non funzionerà quando si usano valori personalizzati in un enum, ma spesso può essere una soluzione semplice.


1

Ho usato quanto segue quando avevo bisogno dei valori minimo e massimo del mio enum. Ho appena impostato un min uguale al valore più basso dell'enumerazione e un max uguale al valore più alto dell'enumerazione come valori enum stessi.

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!");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.