Mendapatkan nilai maksimal enum

148

Bagaimana Anda mendapatkan nilai maksimal enum?

jdelator
sumber
1
Kemungkinan duplikat untuk Menemukan Nilai Tertinggi dalam Pencacahan
Ian Goldby
1
Saya akan berpikir bahwa kompiler dapat menangani ini, daripada menggunakan panggilan Refleksi. Jawaban yang menggunakan metode waktu kompilasi untuk informasi ini akan menerima suara saya.
palswim

Jawaban:

214

Enum.GetValues ​​() tampaknya mengembalikan nilai secara berurutan, sehingga Anda dapat melakukan sesuatu seperti ini:

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

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

Edit

Bagi mereka yang tidak mau membaca komentar: Anda juga dapat melakukannya dengan cara ini:

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

... yang akan berfungsi ketika beberapa nilai enum Anda negatif.

Matt Hamilton
sumber
3
bagus. mengambil keuntungan dari: "Elemen-elemen array diurutkan berdasarkan nilai-nilai biner dari konstanta enumerasi." dari msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi
2
Aku memukul kepalaku, berpikir ini benar-benar sepele tetapi solusi elegan diberikan. Juga jika Anda ingin mendapatkan nilai enum gunakan Convert.ToInt32 () sesudahnya. Ini untuk hasil google.
jdelator
54
Jika Anda akan menggunakan LINQ, mengapa tidak menggunakan Max (), yang jauh lebih jelas, dan tidak bergantung pada "sepertinya"?
Marc Gravell
3
Berkinerja lebih baik, tetapi hanya jika nilai-nilai enum tidak negatif, yang mereka bisa.
ICR
4
Saya memilih Max () juga. Yang Terakhir () akan gagal jika enum tidak negatif, lihat di sini
AZ.
42

Saya setuju dengan jawaban Matt. Jika Anda hanya perlu nilai int minimum dan maksimum, maka Anda dapat melakukannya sebagai berikut.

Maksimum:

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

Minimum:

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

Menurut jawaban Matt Hamilton, saya berpikir untuk membuat metode Extension untuk itu.

Karena ValueTypetidak diterima sebagai jenis parameter kendala generik, saya tidak menemukan cara yang lebih baik untuk membatasi Tke Enumtapi berikut ini.

Setiap ide akan sangat dihargai.

PS. tolong abaikan VB implisit saya, saya suka menggunakan VB dengan cara ini, itulah kekuatan VB dan itulah mengapa saya suka VB.

Howeva, ini dia:

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
sumber
Lihat stackoverflow.com/questions/79126/… untuk ini: if (! Type.IsEnum)
Concrete Gannet
Anda juga dapat menambahkan "struct" ke mana Anda karena ini akan memastikan itu adalah ValueType tetapi tidak membatasi untuk Enum Ini adalah apa yang saya gunakan: di mana T: struct, IComparable, IFormattable
jdawiz
2
Anda dapat memperbarui jawaban Anda. Dalam C # 7.3 Anda benar-benar bisa melakukan metode ekstensi dan juga membatasi ke tipe Enum (bukan struct).
Nordes
Ini bukan metode ekstensi . Tapi metode utilitas yang bagus.
Ray
14

Ini sedikit nitpicky tetapi nilai maksimum sebenarnya enumadalah Int32.MaxValue(dengan asumsi itu enumberasal dari int). Adalah sah untuk memberikan Int32nilai apa pun, enumterlepas dari apakah itu benar-benar menyatakan anggota dengan nilai itu atau tidak.

Hukum:

enum SomeEnum
{
    Fizz = 42
}

public static void SomeFunc()
{
    SomeEnum e = (SomeEnum)5;
}
JaredPar
sumber
Saya punya kasus di mana pengaturan variabel Integer ke enum kembali gagal dengan tipe mismatch ketika nilai gila diberikan, jadi lebih baik menggunakan Long sebagai gantinya (jika Anda malas tidak menjebak kesalahan dengan benar!).
AjV Jsy
9

Setelah mencoba lain kali, saya mendapatkan metode ekstensi ini:

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
sumber
5

Gunakan fungsi Terakhir tidak bisa mendapatkan nilai maksimal. Gunakan fungsi "maks" bisa. Suka:

 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
sumber
4

Dalam perjanjian dengan Matthew J Sullivan, untuk C #:

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

Saya benar-benar tidak yakin mengapa ada orang yang ingin menggunakan:

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

... Seperti kata demi kata, secara semantik, sepertinya tidak masuk akal? (selalu baik untuk memiliki cara yang berbeda, tetapi saya tidak melihat manfaatnya dalam yang terakhir.)

Insinyur
sumber
4
Menggunakan GetUpperBound mengembalikan hitungan (4, bukan 40) untuk saya: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe
Tangkapan yang bagus, aku tidak memperhatikan itu. OK, jadi versi ini bagus untuk enum otomatis standar, tetapi tidak untuk enum dengan nilai khusus. Saya kira pemenangnya tetap Pak Hamilton. :)
Engineer
GetUpperBound baik ketika Enum Anda memiliki nilai bitwise. (yaitu - 1, 2, 4, 8, dll). Misalnya, jika Anda menulis tes unit, Anda ingin bekerja melalui loop dengan iterasi yang banyak: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX
Apa yang salah dengan Panjang (untuk jumlah nilai dalam enum)? Lebih sederhana lebih baik. (Bukannya ini menjawab pertanyaan aslinya.)
Ian Goldby
2

Ada metode untuk mendapatkan informasi tentang jenis yang disebutkan di bawah System.Enum.

Jadi, dalam proyek VB.Net di Visual Studio saya bisa mengetik "System.Enum." dan intellisense memunculkan segala macam kebaikan.

Salah satu metode khususnya adalah System.Enum.GetValues ​​(), yang mengembalikan array dari nilai yang disebutkan. Setelah mendapatkan array, Anda harus dapat melakukan apa pun yang sesuai untuk keadaan khusus Anda.

Dalam kasus saya, nilai yang saya hitung dimulai dari nol dan tidak ada angka, jadi untuk mendapatkan nilai maksimum untuk enum saya, saya hanya perlu tahu berapa banyak elemen dalam array.

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

'''''''

sumber
Tidak berfungsi saat array memiliki celah. Ini juga berfungsi hanya secara tidak sengaja, karena indeks elemen terjadi sama dengan nilai yang disimpan pada indeks itu. GetUpperBound()mengambil indeks setinggi mungkin dalam array yang dikembalikan oleh GetValues(), bukan nilai tertinggi yang disimpan di dalam array itu.
JensG
2

Di F #, dengan fungsi helper untuk mengonversi enum ke urutan:

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   

Menjalankannya ...

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

Tidak when 'A : enum<'B>diperlukan oleh kompiler untuk definisi, tetapi diperlukan untuk setiap penggunaan ToSeq, bahkan oleh tipe enum yang valid.

Stephen Hosking
sumber
1

Ini tidak dapat digunakan dalam semua situasi, tetapi saya sendiri sering mendefinisikan nilai maks:

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

Tentu saja ini tidak akan berfungsi ketika Anda menggunakan nilai khusus dalam enum, tetapi seringkali itu bisa menjadi solusi yang mudah.

yvan vander sanden
sumber
1

Saya menggunakan berikut ini ketika saya membutuhkan nilai min dan max enum saya. Saya hanya menetapkan min sama dengan nilai terendah enumerasi dan max sama dengan nilai tertinggi dalam enumerasi sebagai nilai enum sendiri.

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
sumber