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


148

Як отримати максимальне значення перерахунку?



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

... що буде спрацьовувати, коли деякі ваші значення перерахунку негативні.


3
приємно. користуючись перевагою: "Елементи масиву сортуються за бінарними значеннями констант перерахування." від msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi

2
Я стукав головою, думаючи, що це справді дрібниця, але було прийнято елегантне рішення. Також якщо ви хочете отримати значення перерахунку, використовуйте Convert.ToInt32 () згодом. Це для результатів google.
jdelator

54
Якщо ви збираєтеся використовувати LINQ, чому б не використовувати Max (), який набагато зрозуміліше і не покладається на "здається"?
Марк Гравелл

3
Він працює краще, але лише у тому випадку, якщо значення перерахунку не є негативними, якими вони могли бути.
ICR

4
Я також голосую за Макса (). Остання () не зможе, якщо перерахунок не негативний, дивіться тут
AZ.

42

Я згоден з відповіддю Метта. Якщо вам потрібні лише мінімальні та максимальні значення 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.

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/… для цього: якщо (! Type.IsEnum)
Бетонний Gannet

Ви також можете додати "struct" до свого, де це забезпечить це ValueType, але не обмежуватиме його Enum. Це те, що я використовую: де T: struct, IComparable, IFormattable
jdawiz

2
Ви можете оновити свою відповідь. У C # 7.3 ви можете фактично зробити метод розширення, а також обмежитися типом Enum (замість структури).
Нордес

Це не метод розширення . Але хороший корисний метод.
Рей

14

Це незначно, але фактичне максимальне значення будь-якого 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

Використання функції "Останній" не могло отримати максимальне значення. Використовувати функцію "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

За погодженням з Метью Дж. Саліван, для 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

Що не так з довжиною (для кількості значень в перерахунку)? Простіше, краще. (Не те, що це відповідає на початкове запитання.)
Ян Голдбі

2

Існують методи отримання інформації про перелічені типи в System.Enum.

Отже, в проекті VB.Net у Visual Studio я можу набрати "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 = 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

Я використовував наступне, коли мені потрібні були мінімальні та максимальні значення моєї перерахунки. Я просто встановив min, рівний найменшому значенню перерахунку і max, рівний найвищому значенню перерахування, як самі значення перерахунків.

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.