รับค่าสูงสุดของ enum


148

คุณจะรับค่าสูงสุดของ enum ได้อย่างไร


1
ความซ้ำซ้อนที่เป็นไปได้ของการหาค่าสูงสุดในการแจงนับ
เอียนโกลด์บาย

1
ฉันคิดว่าคอมไพเลอร์สามารถจัดการกับสิ่งนี้ได้มากกว่าที่จะใช้การเรียก Reflection คำตอบที่ใช้วิธีการรวบรวมเวลาสำหรับข้อมูลนี้จะได้รับการโหวตของฉัน
palswim

คำตอบ:


214

Enum.GetValues ​​() ดูเหมือนว่าจะส่งกลับค่าตามลำดับดังนั้นคุณสามารถทำสิ่งนี้:

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

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

แก้ไข

สำหรับผู้ที่ไม่ต้องการอ่านความคิดเห็น: คุณสามารถทำเช่นนี้ได้:

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

... ซึ่งจะทำงานเมื่อค่า enum ของคุณบางค่าเป็นลบ


3
ดี การใช้ประโยชน์จาก: "องค์ประกอบของอาร์เรย์จะถูกเรียงลำดับตามค่าไบนารีของค่าคงที่การแจงนับ" จากmsdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi

2
ฉันตีหัวของฉันคิดว่านี่เป็นเรื่องจริงมาก แต่ได้รับการแก้ปัญหาที่สง่างาม นอกจากนี้หากคุณต้องการรับค่า enum ให้ใช้ Convert.ToInt32 () หลังจากนั้น นี่คือผลลัพธ์ของ google
jdelator

54
หากคุณกำลังจะใช้งาน LINQ ทำไมไม่ใช้ Max () ซึ่งชัดเจนกว่าและไม่พึ่งพา "ดูเหมือนจะ"
Marc Gravell

3
มันทำงานได้ดีขึ้น แต่ถ้าค่าของ enum นั้นไม่เป็นลบเท่านั้น
ICR

4
ฉันลงคะแนนให้ Max () ด้วย Last () จะล้มเหลวหาก enum ไม่เป็นลบให้ดูที่นี่
AZ

42

ฉันเห็นด้วยกับคำตอบของ Matt หากคุณต้องการเพียงค่า min และ max int คุณสามารถทำได้ดังนี้

ขีดสุด:

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

จำนวนขั้นต่ำ:

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

21

ตามคำตอบของ Matt Hamilton ฉันคิดว่าการสร้างวิธีการขยายสำหรับมัน

เนื่องจากValueTypeไม่ได้รับการยอมรับว่าเป็นข้อ จำกัด ประเภททั่วไปพารามิเตอร์ฉันไม่พบวิธีที่ดีกว่าที่จะ จำกัดTการEnumแต่ต่อไปนี้

ความคิดใด ๆ ที่จะได้รับการชื่นชมจริงๆ

PS โปรดเพิกเฉยต่อ VB implicitness ของฉันฉันชอบใช้ VB ด้วยวิธีนี้นั่นคือจุดแข็งของ VB และนั่นคือเหตุผลที่ฉันรัก VB

Howeva นี่คือ:

ค#:

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

ดูstackoverflow.com/questions/79126/…สำหรับสิ่งนี้: if (! type.IsEnum)
Concrete Gannet

คุณสามารถเพิ่ม "struct" ลงในที่ซึ่งจะทำให้แน่ใจว่าเป็น ValueType แต่ไม่ จำกัด เฉพาะ Enum นี่คือสิ่งที่ฉันใช้: โดยที่ T: struct, IComparable, IFormattable
jdawiz

2
คุณสามารถปรับปรุงคำตอบของคุณ ใน C # 7.3 คุณสามารถทำตามวิธีการขยายและ จำกัด ประเภท Enum (แทนที่จะเป็น struct)
Nordes

นี่ไม่ใช่วิธีการขยายแม้ว่า แต่วิธียูทิลิตี้ที่ดี
เรย์

14

นี่เป็น nitpicky เล็กน้อย แต่มูลค่าสูงสุดที่แท้จริงของใด ๆenumคือInt32.MaxValue(สมมติว่ามันenumมาจากint) เป็นเรื่องถูกกฎหมายอย่างสมบูรณ์ที่จะนำInt32มูลค่าใด ๆไปใช้enumโดยไม่คำนึงว่าจะประกาศสมาชิกด้วยมูลค่านั้นหรือไม่

กฎหมาย:

enum SomeEnum
{
    Fizz = 42
}

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

ฉันเคยมีกรณีที่การตั้งค่าตัวแปร Integer ให้กับ enum ที่ส่งคืนล้มเหลวด้วยชนิดไม่ตรงกันเมื่อมีการให้ค่าบ้าดังนั้นจึงควรใช้ Long แทน (ถ้าคุณขี้เกียจไม่ติดกับข้อผิดพลาดอย่างถูกต้อง!)
AjV Jsy

9

หลังจากลองอีกครั้งฉันได้รับวิธีการขยายนี้:

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

ใช้ฟังก์ชั่นสุดท้ายไม่สามารถรับค่าสูงสุด ใช้ฟังก์ชั่น "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)
        {
            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

ตามข้อตกลงกับ Matthew J Sullivan สำหรับ C #:

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

ฉันไม่แน่ใจจริงๆว่าทำไมทุกคนต้องการใช้:

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

... ในฐานะที่เป็นคำต่อคำพูดเชิงความหมายดูเหมือนจะไม่สมเหตุสมผลใช่ไหม? (ดีเสมอที่จะมีวิธีต่าง ๆ แต่ฉันไม่เห็นประโยชน์ในภายหลัง)


4
การใช้ GetUpperBound คืนค่าการนับ (4 ไม่ใช่ 40) สำหรับฉัน: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe

จับดีฉันไม่ได้สังเกตว่า ตกลงดังนั้นรุ่นนี้ยอดเยี่ยมสำหรับ enums อัตโนมัติมาตรฐาน แต่ไม่ใช่สำหรับ enums ด้วยค่าที่กำหนดเอง ฉันเดาว่าผู้ชนะจะยังคงเป็นนายแฮมิลตัน :)
วิศวกร

GetUpperBound นั้นดีเมื่อ Enum ของคุณมีค่า bitwise (เช่น - 1, 2, 4, 8, ฯลฯ ) ตัวอย่างเช่นหากคุณกำลังเขียนการทดสอบหน่วยคุณต้องการทำงานผ่านลูปที่มีการวนซ้ำหลายครั้ง: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)) GetUpperBound (0))
WEFX

เกิดอะไรขึ้นกับความยาว (สำหรับจำนวนของค่าใน enum) ง่ายกว่าดีกว่า (ไม่ว่าข้อมูลนี้สามารถตอบคำถามเดิม.)
เอียน Goldby

2

มีวิธีการรับข้อมูลเกี่ยวกับประเภทที่ระบุภายใต้ System.Enum

ดังนั้นในโครงการ VB.Net ใน Visual Studio ฉันสามารถพิมพ์ "System.Enum" และ Intellisense นำมาซึ่งความดีทุกประเภท

วิธีการหนึ่งโดยเฉพาะอย่างยิ่งคือ System.Enum.GetValues ​​() ซึ่งส่งกลับอาร์เรย์ของค่าที่แจกแจง เมื่อคุณได้รับชุดคุณควรจะสามารถทำสิ่งที่เหมาะสมกับสถานการณ์ของคุณ

ในกรณีของฉันค่าที่แจกแจงของฉันเริ่มต้นที่ศูนย์และไม่ต้องข้ามตัวเลขดังนั้นเพื่อให้ได้ค่าสูงสุดสำหรับ enum ของฉันฉันแค่ต้องรู้ว่ามีองค์ประกอบอยู่ในอาร์เรย์เท่าใด

ตัวอย่างโค้ด 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")

'''''''

ไม่ทำงานเมื่ออาร์เรย์มีช่องว่าง นอกจากนี้ยังใช้งานได้โดยอุบัติเหตุเท่านั้นเนื่องจากดัชนีองค์ประกอบเกิดขึ้นเท่ากับค่าที่เก็บไว้ในดัชนีนั้น GetUpperBound()ดึงดัชนีที่เป็นไปได้สูงสุดในอาร์เรย์ที่ส่งคืนโดยGetValues()ไม่ใช่ค่าสูงสุดที่เก็บไว้ในอาร์เรย์นั้น
JensG

2

ใน F # ด้วยฟังก์ชันตัวช่วยในการแปลง enum เป็นลำดับ:

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   

เรียกใช้ ...

> พิมพ์ Foo = | Fizz = 3 | บาง = 2
> val ToSeq: 'A -> seq <' B> เมื่อ 'A: enum <' B>
> val FooMax: Foo = Fizz

when 'A : enum<'B>ไม่จำเป็นต้องใช้คอมไพเลอร์สำหรับความหมาย แต่เป็นสิ่งจำเป็นสำหรับการใช้งานของ ToSeq ใด ๆ แม้โดยแบ่งตามชนิด enum ที่ถูกต้อง


1

มันไม่สามารถใช้งานได้ในทุกสถานการณ์ แต่ฉันมักจะกำหนดค่าสูงสุดด้วยตนเอง:

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

แน่นอนว่าสิ่งนี้จะไม่ทำงานเมื่อคุณใช้ค่าที่กำหนดเองใน enum แต่บ่อยครั้งอาจเป็นวิธีแก้ปัญหาที่ง่าย


1

ฉันใช้สิ่งต่อไปนี้เมื่อฉันต้องการค่า min และค่าสูงสุดของ enum ของฉัน ฉันเพิ่งตั้งค่านาทีเท่ากับค่าต่ำสุดของการแจงนับและสูงสุดเท่ากับค่าสูงสุดในการแจงนับเป็นค่า enum ตัวเอง

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!");
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.