Lấy giá trị tối đa của một enum


147

Làm thế nào để bạn có được giá trị tối đa của một enum?



1
Tôi nghĩ rằng trình biên dịch có thể xử lý việc này, thay vì sử dụng lệnh gọi Reflection. Một câu trả lời sử dụng phương pháp biên dịch thời gian cho thông tin này sẽ nhận được phiếu bầu của tôi.
palswim

Câu trả lời:


214

Enum.GetValues ​​() dường như trả về các giá trị theo thứ tự, vì vậy bạn có thể làm một cái gì đó như thế này:

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

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

Biên tập

Đối với những người không sẵn sàng đọc qua các bình luận: Bạn cũng có thể làm theo cách này:

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

... sẽ hoạt động khi một số giá trị enum của bạn âm.


3
đẹp. lợi dụng: "Các phần tử của mảng được sắp xếp theo các giá trị nhị phân của các hằng số liệt kê." từ msdn.microsoft.com/en-us/l Library / system.enum.getvalues.aspx
TheSoftwareJedi

2
Tôi đã đập đầu mình, nghĩ rằng điều này thực sự là trival nhưng một giải pháp tao nhã đã được đưa ra. Ngoài ra nếu bạn muốn nhận giá trị enum, hãy sử dụng Convert.ToInt32 () sau đó. Đây là kết quả của google.
jdelator

53
Nếu bạn sẽ sử dụng LINQ, tại sao không sử dụng Max (), rõ ràng hơn nhiều và không dựa vào "dường như"?
Marc Gravell

3
Nó hoạt động tốt hơn, nhưng chỉ khi các giá trị của enum không âm, mà chúng có thể là.
ICR

4
Tôi cũng bình chọn cho Max (). Lần cuối () sẽ thất bại nếu enum không âm, xem tại đây
AZ.

41

Tôi đồng ý với câu trả lời của Matt. Nếu bạn chỉ cần các giá trị tối thiểu và tối đa, thì bạn có thể làm như sau.

Tối đa:

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

Tối thiểu:

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

21

Theo câu trả lời của Matt Hamilton, tôi đã nghĩ đến việc tạo ra một phương thức mở rộng cho nó.

Kể từ khi ValueTypekhông được chấp nhận như là một hạn chế tham số kiểu chung chung, tôi không tìm thấy một cách tốt hơn để hạn chế Tđến Enumnhưng sau.

Bất kỳ ý tưởng sẽ được thực sự đánh giá cao.

Tái bút xin vui lòng bỏ qua nhân chứng VB của tôi, tôi thích sử dụng VB theo cách này, đó là thế mạnh của VB và đó là lý do tại sao tôi yêu VB.

Howeva, đây là:

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

Xem stackoverflow.com/questions/79126/ trên để biết điều này: if (! Type.IsEnum)
Concrete Gannet

bạn cũng có thể thêm "struct" vào vị trí của mình vì điều này sẽ đảm bảo nó là ValueType nhưng không giới hạn nó ở Enum Đây là thứ tôi sử dụng: trong đó T: struct, IComparable,
IFormattable

2
Bạn có thể cập nhật câu trả lời của bạn. Trong C # 7.3, bạn thực sự có thể thực hiện phương thức mở rộng và cũng hạn chế loại Enum (thay vì struct).
Nordes

Đây không phải là một phương pháp mở rộng mặc dù. Nhưng một phương pháp tiện ích tốt.
Ray

14

Điều này hơi nitpicky nhưng giá trị tối đa thực tế của bất kỳ enumInt32.MaxValue(giả sử nó enumcó nguồn gốc từ int). Hoàn toàn hợp pháp khi đưa bất kỳ Int32giá trị nào cho bất kỳ giá trị nào, bất enumkể nó có thực sự tuyên bố thành viên có giá trị đó hay không.

Hợp pháp:

enum SomeEnum
{
    Fizz = 42
}

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

Tôi đã gặp trường hợp đặt biến số nguyên thành enum trả về không thành công với kiểu không khớp khi cung cấp giá trị điên, vì vậy tốt nhất là sử dụng Long thay thế (nếu bạn lười biếng không đặt bẫy đúng cách!).
AjV Jsy

9

Sau khi thử một lần khác, tôi đã nhận được phương thức mở rộng này:

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

Sử dụng chức năng Cuối cùng không thể có được giá trị tối đa. Sử dụng chức năng "tối đa" có thể. Giống:

 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

Đồng ý với Matthew J Sullivan, cho C #:

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

Tôi thực sự không chắc chắn tại sao mọi người muốn sử dụng:

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

... Là từng từ, nói theo ngữ nghĩa, nó dường như không có ý nghĩa nhiều như vậy? (luôn luôn tốt để có những cách khác nhau, nhưng tôi không thấy lợi ích sau này.)


4
Sử dụng GetUpperBound trả lại số đếm (4, không phải 40) cho tôi: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe 17/03/2016

Bắt tốt đẹp, tôi đã không nhận thấy điều đó. OK, vì vậy phiên bản này là tuyệt vời cho enum tự động tiêu chuẩn, nhưng không phải cho enum với giá trị tùy chỉnh. Tôi đoán người chiến thắng vẫn là ông Hamilton. :)
Kỹ sư

GetUpperBound là tốt khi Enum của bạn có giá trị bitwise. (tức là - 1, 2, 4, 8, v.v.). Chẳng hạn, nếu bạn đang viết một bài kiểm tra đơn vị, bạn sẽ muốn thực hiện một vòng lặp với nhiều lần lặp này: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX

Có gì sai với Độ dài (đối với số lượng giá trị trong enum)? Đơn giản hơn. (Không phải điều này trả lời câu hỏi ban đầu.)
Ian Goldby

2

Có các phương pháp để nhận thông tin về các kiểu liệt kê trong System.Enum.

Vì vậy, trong một dự án VB.Net trong Visual Studio, tôi có thể gõ "System.Enum." và intellisense mang đến tất cả các loại lòng tốt.

Một phương thức cụ thể là System.Enum.GetValues ​​(), trả về một mảng các giá trị được liệt kê. Khi bạn đã có được mảng, bạn sẽ có thể làm bất cứ điều gì phù hợp với hoàn cảnh cụ thể của bạn.

Trong trường hợp của tôi, các giá trị được liệt kê của tôi bắt đầu từ 0 và không bỏ qua các số nào, vì vậy để có được giá trị tối đa cho enum của tôi, tôi chỉ cần biết có bao nhiêu phần tử trong mảng.

Đoạn mã 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")

'''''''

Không hoạt động khi mảng có khoảng trống. Nó cũng chỉ hoạt động một cách tình cờ, bởi vì chỉ số phần tử xảy ra bằng với giá trị được lưu trữ tại chỉ mục đó. GetUpperBound()lấy chỉ số cao nhất có thể trong mảng được trả về GetValues(), không phải giá trị cao nhất được lưu trữ bên trong mảng đó.
JensG

2

Trong F #, với chức năng trợ giúp để chuyển enum thành chuỗi:

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   

Chạy nó ...

> gõ Foo = | Fizz = 3 | Bang = 2
> val ToSeq: 'A -> seq <' B> khi 'A: enum <' B>
> val FooMax: Foo = Fizz

Các when 'A : enum<'B>không theo yêu cầu của trình biên dịch cho các định nghĩa, nhưng là cần thiết cho bất kỳ sử dụng ToSeq, thậm chí theo một kiểu enum hợp lệ.


1

Nó không thể sử dụng được trong mọi trường hợp, nhưng tôi thường tự xác định giá trị tối đa:

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

Tất nhiên điều này sẽ không hoạt động khi bạn sử dụng các giá trị tùy chỉnh trong enum, nhưng thường thì nó có thể là một giải pháp dễ dàng.


1

Tôi đã sử dụng như sau khi tôi cần các giá trị tối thiểu và tối đa của enum của tôi. Tôi chỉ đặt một phút bằng giá trị liệt kê thấp nhất và tối đa bằng giá trị cao nhất trong bảng liệt kê như chính giá trị 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!");
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.