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


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.