Obtendo o valor máximo de uma enumeração


Respostas:


214

Enum.GetValues ​​() parece retornar os valores em ordem, para que você possa fazer algo assim:

// given this enum:
public enum Foo
{
    Fizz = 3, 
    Bar = 1,
    Bang = 2
}

// this gets Fizz
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Last();

Editar

Para aqueles que não desejam ler os comentários: Você também pode fazer o seguinte:

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

... que funcionará quando alguns de seus valores de enumeração forem negativos.


3
legais. aproveitando: "Os elementos da matriz são classificados pelos valores binários das constantes de enumeração." de msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi 15/10/2008

2
Eu estava batendo na minha cabeça, pensando que isso era realmente um rival, mas uma solução elegante foi dada. Além disso, se você deseja obter o valor da enumeração, use Convert.ToInt32 () posteriormente. Isto é para os resultados do google.
jdelator

53
Se você usar o LINQ, por que não usar Max (), que é muito mais claro e não depende de "parece"?
Marc Gravell

3
Ele tem um desempenho melhor, mas somente se os valores da enumeração não forem negativos, o que poderiam ser.
ICR

4
Também voto em Max (). O Last () falharia se o enum não fosse negativo, veja aqui
AZ.

41

Eu concordo com a resposta de Matt. Se você precisar apenas de valores mínimo e máximo int, poderá fazê-lo da seguinte maneira.

Máximo:

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

Mínimo:

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

21

De acordo com a resposta de Matt Hamilton, pensei em criar um método de extensão para ele.

Como ValueTypenão é aceito como uma restrição de parâmetro de tipo genérico, não encontrei uma maneira melhor de restringir TaEnum , mas o seguinte.

Qualquer idéia seria realmente apreciada.

PS. por favor, ignore minha implicitude VB, eu amo usar VB dessa maneira, essa é a força do VB e é por isso que eu amo VB.

Howeva, aqui está:

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

Veja stackoverflow.com/questions/79126/… para isso: if (! Type.IsEnum)
Concrete Gannet

você também pode adicionar "struct" para o seu onde, como isso irá garantir que ele é um ValueType, mas não restringi-lo a Enum Isto é o que eu uso: onde T: struct, IComparable, IFormattable
jdawiz

2
Você pode atualizar sua resposta. No C # 7.3, você poderia realmente executar o método de extensão e também restringir ao tipo Enum (em vez de struct).
Nordes

Este não é um método de extensão . Mas um bom método de utilidade.
Ray

14

Isso é um pouco complicado, mas o valor máximo real de qualquer um enumé Int32.MaxValue(assumindo que seja enumderivado de int). É perfeitamente legal converter qualquer Int32valor para qualquer um, enumindependentemente de ter ou não declarado um membro com esse valor.

Legal:

enum SomeEnum
{
    Fizz = 42
}

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

Já tive casos em que a definição de uma variável Integer para uma enum retornada falha com a incompatibilidade de tipo quando um valor louco é fornecido, por isso é melhor usar um Long (se você não estiver prendendo o erro corretamente!).
AJV JSY

9

Depois de tentar outra vez, obtive este método de extensão:

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

Use a função Last não pôde obter o valor máximo. Use a função "max" poderia. Gostar:

 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

De acordo com Matthew J Sullivan, para C #:

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

Eu realmente não sei por que alguém iria querer usar:

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

... Como palavra por palavra, semanticamente falando, não parece fazer tanto sentido? (sempre bom ter maneiras diferentes, mas não vejo o benefício no último.)


4
Usar GetUpperBound retorna uma contagem (4, não 40) para mim: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe

Boa captura, eu não tinha notado isso. OK, então esta versão é ótima para enumerações automáticas padrão, mas não para enumerações com valores personalizados. Acho que o vencedor continua sendo o senhor Hamilton. :)
Engenheiro

GetUpperBound é bom quando seu Enum possui valores bit a bit. (ie - 1, 2, 4, 8, etc). Por exemplo, se você estivesse escrevendo um teste de unidade, desejaria trabalhar com um loop com muitas iterações: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX 18/08/19

O que há de errado com Comprimento (para o número de valores na enumeração)? Mais simples é melhor. (Não que isso responde à pergunta original.)
Ian Goldby

2

Existem métodos para obter informações sobre tipos enumerados em System.Enum.

Portanto, em um projeto VB.Net no Visual Studio, posso digitar "System.Enum". e o intellisense traz todo tipo de bondade.

Um método em particular é System.Enum.GetValues ​​(), que retorna uma matriz dos valores enumerados. Depois de obter a matriz, você poderá fazer o que for apropriado para suas circunstâncias particulares.

No meu caso, meus valores enumerados começaram em zero e não saltaram nenhum número; portanto, para obter o valor máximo da minha enumeração, só preciso saber quantos elementos estavam na matriz.

Fragmentos de código 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")

'''''''

Não funciona quando a matriz tem lacunas. Também funciona apenas por acidente, porque o índice do elemento é igual ao valor armazenado nesse índice. GetUpperBound()recupera o índice mais alto possível na matriz retornada por GetValues(), não o valor mais alto armazenado dentro dessa matriz.
JensG 01/06/19

2

No F #, com uma função auxiliar para converter o enum em uma sequência:

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   

Executando ...

> tipo Foo = | Fizz = 3 | Bang = 2
> val ToSeq: 'A -> seq <' B> quando 'A: enum <' B>
> val FooMax: Foo = Fizz

O when 'A : enum<'B>não é exigido pelo compilador para a definição, mas é necessário para qualquer uso do ToSeq, mesmo por um tipo de enumeração válido.


1

Não é utilizável em todas as circunstâncias, mas geralmente eu mesmo defino o valor máximo:

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

Obviamente, isso não funcionará quando você usar valores personalizados em uma enumeração, mas geralmente pode ser uma solução fácil.


1

Usei o seguinte quando precisei dos valores mínimo e máximo da minha enumeração. Acabei de definir um mínimo igual ao valor mais baixo da enumeração e um valor máximo igual ao valor mais alto na enumeração, já que os próprios valores da enumeração.

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!");
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.