Получение максимального значения перечисления


148

Как вы получаете максимальное значение перечисления?


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 (), который намного понятнее и не полагается на «кажется»?
— Марк Гравелл

3
Это работает лучше, но только если значения перечисления не отрицательны, какими они могли бы быть.
— ICR

4
Я тоже голосую за Макса (). Last () потерпит неудачу, если enum не отрицателен, смотрите здесь
— AZ.

42

Я согласен с ответом Мэтта. Если вам нужны только значения min и max int, то вы можете сделать это следующим образом.

Максимум:

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

Минимум:

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

21

Согласно ответу Мэтта Гамильтона, я подумал о создании для него метода Extension.

Так ValueTypeне принят в качестве общего ограничения параметров типа, я не нашел лучший способ ограничить Tдо , Enumно ниже.

Любые идеи будут по достоинству оценены.

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

См. Stackoverflow.com/questions/79126/… для этого: if (! Type.IsEnum)
— Бетонная олуша

вы также можете добавить «struct» к вашему where, так как это будет гарантировать, что это ValueType, но не ограничивать его перечислением. Это то, что я использую: где T: struct, IComparable, IFormattable
— jdawiz

2
Вы можете обновить свой ответ. В C # 7.3 вы могли бы на самом деле сделать метод расширения, а также ограничиться типом Enum (вместо struct).
— Нордес

Это не метод расширения, хотя. Но хороший полезный метод.
— Рэй

14

Это немного nitpicky , но фактическое максимальное значение любого enumявляется Int32.MaxValue(при условии , что это enumпроисходит от int). Совершенно законно приводить любое Int32значение к любому enumнезависимо от того, действительно ли оно объявило члена с этим значением.

Допустимо:

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

По согласованию с Мэтью Дж Салливаном, для 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

Хороший улов, я этого не заметил. Итак, эта версия отлично подходит для стандартных автоматических перечислений, но не для перечислений с пользовательскими значениями. Я думаю, что победителем остается мистер Гамильтон. :)
— инженер

GetUpperBound хорош, когда ваш Enum имеет побитовые значения. (т.е. - 1, 2, 4, 8 и т. д.). Например, если вы писали модульный тест, вы бы хотели работать через цикл с таким количеством итераций: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
— WEFX

Что не так с Length (для количества значений в перечислении)? Проще лучше. (Не то чтобы это
— отвечало

2

Существуют методы для получения информации о перечисляемых типах в System.Enum.

Итак, в проекте VB.Net в Visual Studio я могу напечатать «System.Enum». и intellisense воспитывает все виды доброты.

В частности, одним из методов является 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 = | Fizz = 3 | Взрыв = 2
> val ToSeq: 'A -> seq <' B> когда 'A: enum <' B>
> val FooMax: Foo = Fizz

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!");
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.