【问题标题】:Getting the max value of an enum获取枚举的最大值
【发布时间】:2010-09-17 05:33:51
【问题描述】:

如何获得枚举的最大值?

【问题讨论】:

标签: c# enums


【解决方案1】:

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

编辑

对于那些不愿意阅读 cmets 的人:你也可以这样做:

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

...当您的某些枚举值为负时,这将起作用。

【讨论】:

  • 不错。利用:“数组的元素按枚举常量的二进制值排序。”来自msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
  • 我当时在摇头,认为这真的很琐碎,但给出了一个优雅的解决方案。此外,如果您想获取枚举值,请在之后使用 Convert.ToInt32() 。这是用于谷歌搜索结果的。
  • 如果你要使用LINQ,为什么不使用Max(),它更清晰,并且不依赖“似乎”?
  • 它的性能更好,但前提是枚举的值不是负数,它们可能是负数。
  • 我也投票给 Max()。如果枚举不是负数,则 Last() 将失败,请参阅 here
【解决方案2】:

我同意马特的回答。如果您只需要最小和最大 int 值,则可以按以下方式进行。

最大值:

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

最低:

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

【讨论】:

    【解决方案3】:

    根据马特汉密尔顿的回答,我想为它创建一个扩展方法。

    由于ValueType 不被接受为泛型类型参数约束,我没有找到更好的方法将T 限制为Enum,但以下。

    任何想法都将不胜感激。

    PS。请忽略我的 VB 含蓄,我喜欢以这种方式使用 VB,这就是 VB 的优势,这就是我喜欢 VB 的原因。

    Howeva,这里是:

    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
    

    【讨论】:

    • 请参阅stackoverflow.com/questions/79126/…:if (!type.IsEnum)
    • 您也可以将“struct”添加到您的 where 因为这将确保它是一个 ValueType 但不将其限制为 Enum 这是我使用的: where T : struct, IComparable, IFormattable
    • 您可以更新您的答案。在 C# 7.3 中,您实际上可以执行扩展方法并限制为 Enum 类型(而不是 struct)。
    • 这不是一个 extension 方法。但是一个很好的实用方法。
    【解决方案4】:

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

    法律:

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

    【讨论】:

    • 我遇到过这样的情况,当提供一个疯狂的值时,将 Integer 变量设置为返回的枚举会因类型不匹配而失败,因此最好使用 Long 来代替(如果你懒惰地不捕获错误正确!)。
    【解决方案5】:

    又试了一次,得到了这个扩展方法:

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

    【讨论】:

      【解决方案6】:

      使用 Last 函数无法获取最大值。使用“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);
              }
          }
      

      【讨论】:

        【解决方案7】:

        与 Matthew J Sullivan 一致,对于 C#:

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

        我真的不知道为什么有人会想要使用:

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

        ...逐字逐句,从语义上讲,它似乎没有多大意义? (有不同的方式总是好的,但我看不到后者的好处。)

        【讨论】:

        • 使用 GetUpperBound 为我返回一个计数(4,而不是 40):MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
        • 很好,我没有注意到。好的,所以这个版本非常适合标准自动枚举,但不适用于具有自定义值的枚举。我猜获胜者仍然是汉密尔顿先生。 :)
        • GetUpperBound 当您的 Enum 具有按位值时很好。 (即 - 1、2、4、8 等)。例如,如果你正在编写一个单元测试,你会想要通过这样多次迭代的循环: Math.Pow(2, Enum.GetValues(typeof(MyEnum)).GetUpperBound(0)) 。跨度>
        • 长度有什么问题(对于枚举中的值的数量)?越简单越好。 (并不是说这回答了最初的问题。)
        【解决方案8】:

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

        因此,在 Visual Studio 的 VB.Net 项目中,我可以键入“System.Enum”。智能感知带来了各种各样的好处。

        一个特别的方法是 System.Enum.GetValues(),它返回一个枚举值的数组。一旦你得到了数组,你应该能够根据你的特定情况做任何合适的事情。

        在我的例子中,我的枚举值从零开始并且没有跳过任何数字,所以要获得我的枚举的最大值,我只需要知道数组中有多少元素。

        VB.Net代码sn-ps:

        '''''''
        
        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() 返回的数组中可能的最高索引,而不是存储在该数组中的最高值。
        【解决方案9】:

        在 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 当'A : enum > val FooMax : Foo = Fizz

        编译器不需要when 'A : enum&lt;'B&gt; 进行定义,但任何使用 ToSeq 时都需要when 'A : enum&lt;'B&gt;,即使是有效的枚举类型也是如此。

        【讨论】:

          【解决方案10】:

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

          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!");
          }
          

          【讨论】:

            【解决方案11】:

            并非在所有情况下都可用,但我经常自己定义最大值:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-07-21
              • 1970-01-01
              • 2022-11-12
              相关资源
              最近更新 更多