获取枚举的最大值


147

如何获得枚举的最大值?



1
我认为编译器可以处理此问题,而不是使用Reflection调用。使用编译时方法获取此信息的答案将受到我的支持。
palswim

Answers:


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

...在某些枚举值为负数时将起作用。


3
很好 利用:“数组的元素按枚举常量的二进制值排序。” 来自msdn.microsoft.com/zh-cn/library/system.enum.getvalues.aspx
TheSoftwareJedi's

2
我拍了拍头,以为这真的很琐碎,但是给出了一个优雅的解决方案。另外,如果要获取枚举值,请在以后使用Convert.ToInt32()。这是给谷歌的结果。
jdelator

53
如果您要使用LINQ,为什么不使用Max(),它更清楚,并且不依赖于“似乎”?
马克·格雷韦尔

3
它的性能更好,但前提是枚举的值不为负(可能为负)。
ICR

4
我也投票支持Max()。最后()会失败,如果枚举不是消极的,看这里
AZ。

41

我同意马特的回答。如果仅需要最小和最大int值,则可以按照以下步骤进行操作。

最大值:

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

最低要求:

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

21

根据Matt Hamilton的回答,我考虑为其创建扩展方法。

由于ValueType不被接受作为一个泛型类型参数的约束,我没有找到一个更好的办法来限制TEnum但下面。

任何想法将不胜感激。

PS。请忽略我的VB隐式性,我喜欢以这种方式使用VB,这就是VB的优势,这就是为什么我喜欢VB。

豪瓦,这是:

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


您还可以将“ struct”添加到您的位置,因为这将确保它是ValueType,但不将其限制为Enum。这就是我使用的方法:where T:struct,IComparable,IFormattable
jdawiz

2
您可以更新您的答案。在C#7.3中,您实际上可以执行扩展方法,并且还限制为Enum类型(而不是struct)。
诺德斯'18

但是,这不是扩展方法。但是是一种很好的实用方法。

14

这有点挑剔,但是任何一个的实际最大值enumInt32.MaxValue(假设它是从enum派生的int)。无论将任何Int32enum实际声明为具有该值的成员,将任何值都转换为any 是完全合法的。

法律:

enum SomeEnum
{
    Fizz = 42
}

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

我曾经遇到过这样的情况:在提供疯狂值时,将Integer变量设置为返回的枚举失败,类型不匹配,因此最好使用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

使用Last函数无法获取最大值。使用“最大”功能即可。喜欢:

 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 2010年

不错,我没注意到。好的,因此此版本适用于标准自动枚举,但不适用于具有自定义值的枚举。我猜赢家仍然是汉密尔顿先生。:)
工程师

当您的Enum具有按位值时,GetUpperBound很好。(即-1、2、4、8等)。例如,如果您正在编写单元测试,则需要遍历循环进行以下多次迭代:Math.Pow(2,Enum.GetValues(typeof(MyEnum))。GetUpperBound(0))。
WEFX

长度(枚举中的值数)有什么问题?越简单越好。(并不是说这回答了原始问题。)
伊恩·戈德

2

在System.Enum下有一些获取有关枚举类型的信息的方法。

因此,在Visual Studio的VB.Net项目中,我可以键入“ System.Enum”。智慧带来了种种善良。

特别是一个方法是System.Enum.GetValues(),它返回枚举值的数组。获得阵列后,您应该能够执行适合您特定情况的任何事情。

就我而言,我的枚举值从零开始,不跳过任何数字,因此要获取枚举的最大值,我只需要知道数组中有多少个元素。

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#中,使用辅助函数将枚举转换为序列:

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 = | 碳酸= 3 | 爆炸= 2
> val ToSeq:'A-> seq <'B>当'A:enum <'B>
> val FooMax:Foo =嘶嘶声

when 'A : enum<'B>不是由编译器定义必需的,但需要使用任何ToSeq的,即使是一个有效的枚举类型。


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

当然,当您在枚举中使用自定义值时,这将不起作用,但是通常这是一个简单的解决方案。


1

当我需要枚举的最小值和最大值时,我使用了以下内容。我只是将最小值设置为枚举的最小值,将最大值设置为枚举的最大值,作为枚举值本身。

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!");
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.