Den Maximalwert einer Aufzählung ermitteln


Antworten:


214

Enum.GetValues ​​() scheint die Werte in der angegebenen Reihenfolge zurückzugeben, sodass Sie Folgendes tun können:

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

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

Bearbeiten

Für diejenigen, die nicht bereit sind, die Kommentare durchzulesen: Sie können dies auch folgendermaßen tun:

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

... was funktioniert, wenn einige Ihrer Aufzählungswerte negativ sind.


3
nett. Ausnutzung: "Die Elemente des Arrays werden nach den Binärwerten der Aufzählungskonstanten sortiert." von msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi

2
Ich schlug mir auf den Kopf und dachte, das sei wirklich trival, aber es wurde eine elegante Lösung gegeben. Wenn Sie den Aufzählungswert erhalten möchten, verwenden Sie anschließend Convert.ToInt32 (). Dies ist für die Google-Ergebnisse.
jdelator

53
Wenn Sie LINQ verwenden möchten, verwenden Sie Max (), das viel klarer ist und sich nicht auf "scheint" verlässt.
Marc Gravell

3
Es funktioniert besser, aber nur, wenn die Werte der Aufzählung nicht negativ sind, was sie sein könnten.
ICR

4
Ich stimme auch für Max (). The Last () würde fehlschlagen, wenn die Aufzählung nicht negativ ist, siehe hier
AZ.

41

Ich stimme Matts Antwort zu. Wenn Sie nur minimale und maximale int-Werte benötigen, können Sie dies wie folgt tun.

Maximal:

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

Minimum:

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

21

Nach der Antwort von Matt Hamilton habe ich darüber nachgedacht, eine Erweiterungsmethode dafür zu erstellen.

Da dies ValueTypenicht als generische Einschränkung für Typparameter akzeptiert wird, habe ich keinen besseren Weg gefunden, mich Tauf EnumFolgendes zu beschränken .

Irgendwelche Ideen wären sehr dankbar.

PS. Bitte ignorieren Sie meine VB-Implizität. Ich liebe es, VB auf diese Weise zu verwenden. Das ist die Stärke von VB und deshalb liebe ich VB.

Howeva, hier ist es:

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

Siehe stackoverflow.com/questions/79126/… für dieses: if (! Type.IsEnum)
Concrete Gannet

Sie können auch "struct" zu Ihrem where hinzufügen, da dies sicherstellt, dass es sich um einen ValueType handelt, aber nicht auf Enum beschränkt. Dies ist, was ich verwende: where T: struct, IComparable, IFormattable
jdawiz

2
Sie können Ihre Antwort aktualisieren. In C # 7.3 können Sie die Erweiterungsmethode tatsächlich ausführen und sich auch auf den Enum-Typ beschränken (anstelle von struct).
Nordes

Dies ist jedoch keine Erweiterungsmethode . Aber eine gute Gebrauchsmethode.
Ray

14

Dies ist etwas pingelig, aber der tatsächliche Maximalwert von jedem enumist Int32.MaxValue(vorausgesetzt, es ist ein enumabgeleiteter von int). Es ist völlig legal, einen Int32Wert in einen beliebigen Wert umzuwandeln, enumunabhängig davon, ob tatsächlich ein Mitglied mit diesem Wert deklariert wurde oder nicht.

Legal:

enum SomeEnum
{
    Fizz = 42
}

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

Ich hatte Fälle, in denen das Setzen einer Integer-Variablen auf eine zurückgegebene Enumeration mit einer Nichtübereinstimmung des Typs fehlschlägt, wenn ein verrückter Wert angegeben wird. Verwenden Sie stattdessen am besten ein Long (wenn Sie den Fehler träge nicht richtig abfangen!).
AjV Jsy

9

Nachdem ich es ein anderes Mal versucht hatte, bekam ich diese Erweiterungsmethode:

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

Verwenden Sie die Funktion Letzte konnte den Maximalwert nicht erhalten. Verwenden Sie die Funktion "max". Mögen:

 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 Übereinstimmung mit Matthew J Sullivan für C #:

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

Ich bin mir wirklich nicht sicher, warum jemand Folgendes verwenden möchte:

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

... Semantisch gesehen scheint es Wort für Wort nicht so sinnvoll zu sein? (Es ist immer gut, verschiedene Wege zu haben, aber ich sehe den Nutzen in letzterem nicht.)


4
Die Verwendung von GetUpperBound gibt für mich eine Anzahl (4, nicht 40) zurück: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe

Netter Fang, das hatte ich nicht bemerkt. OK, diese Version eignet sich hervorragend für Standard-Auto-Enums, jedoch nicht für Enums mit benutzerdefinierten Werten. Ich denke, der Gewinner bleibt Herr Hamilton. :)
Ingenieur

GetUpperBound ist gut, wenn Ihre Aufzählung bitweise Werte hat. (dh - 1, 2, 4, 8 usw.). Wenn Sie beispielsweise einen Komponententest schreiben, möchten Sie eine Schleife mit so vielen Iterationen durcharbeiten: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX

Was ist los mit Länge (für die Anzahl der Werte in der Aufzählung)? Einfacher ist besser. (Nicht, dass dies die ursprüngliche Frage beantwortet.)
Ian Goldby

2

Unter System.Enum gibt es Methoden zum Abrufen von Informationen zu Aufzählungstypen.

In einem VB.Net-Projekt in Visual Studio kann ich also "System.Enum" eingeben. und der Intellisense bringt alle Arten von Güte hervor.

Eine Methode ist insbesondere System.Enum.GetValues ​​(), die ein Array der aufgezählten Werte zurückgibt. Sobald Sie das Array haben, sollten Sie in der Lage sein, alles zu tun, was für Ihre besonderen Umstände angemessen ist.

In meinem Fall begannen meine Aufzählungswerte bei Null und übersprangen keine Zahlen. Um den Maximalwert für meine Aufzählung zu erhalten, muss ich nur wissen, wie viele Elemente sich im Array befanden.

VB.Net-Code-Schnipsel:

'''''''

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

'''''''

Funktioniert nicht, wenn das Array Lücken aufweist. Es funktioniert auch nur aus Versehen, da der Elementindex zufällig dem in diesem Index gespeicherten Wert entspricht. GetUpperBound()Ruft den höchstmöglichen Index in dem von zurückgegebenen Array ab GetValues(), nicht den höchsten in diesem Array gespeicherten Wert.
JensG

2

In F # mit einer Hilfsfunktion zum Konvertieren der Aufzählung in eine Sequenz:

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   

Laufen es ...

> Geben Sie Foo = | ein Fizz = 3 | Bang = 2
> val ToSeq: 'A -> seq <' B> wenn 'A: enum <' B>
> val FooMax: Foo = Fizz

Das when 'A : enum<'B>wird vom Compiler für die Definition nicht benötigt, ist jedoch für jede Verwendung von ToSeq erforderlich, selbst für einen gültigen Aufzählungstyp.


1

Es ist nicht unter allen Umständen verwendbar, aber ich definiere den Maximalwert oft selbst:

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

Dies funktioniert natürlich nicht, wenn Sie benutzerdefinierte Werte in einer Aufzählung verwenden, aber häufig kann dies eine einfache Lösung sein.


1

Ich habe Folgendes verwendet, als ich die Min- und Max-Werte meiner Aufzählung benötigte. Ich habe gerade ein min gleich dem niedrigsten Wert der Aufzählung und ein max gleich dem höchsten Wert in der Aufzählung als Aufzählungswerte selbst gesetzt.

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!");
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.