C # Iterando por meio de um enum? (Indexando um System.Array)


113

Eu tenho o seguinte código:

// Obtain the string names of all the elements within myEnum 
String[] names = Enum.GetNames( typeof( myEnum ) );

// Obtain the values of all the elements within myEnum 
Array values = Enum.GetValues( typeof( myEnum ) );

// Print the names and values to file
for ( int i = 0; i < names.Length; i++ )
{
    print( names[i], values[i] ); 
}

No entanto, não posso indexar valores. Existe uma maneira mais fácil de fazer isso?

Ou perdi algo totalmente!

Respostas:


204
Array values = Enum.GetValues(typeof(myEnum));

foreach( MyEnum val in values )
{
   Console.WriteLine (String.Format("{0}: {1}", Enum.GetName(typeof(MyEnum), val), val));
}

Ou você pode lançar o System.Array que é retornado:

string[] names = Enum.GetNames(typeof(MyEnum));
MyEnum[] values = (MyEnum[])Enum.GetValues(typeof(MyEnum));

for( int i = 0; i < names.Length; i++ )
{
    print(names[i], values[i]);
}

Mas, você pode ter certeza de que GetValues ​​retorna os valores na mesma ordem em que GetNames retorna os nomes?


3
"Mas, você pode ter certeza de que GetValues ​​retorna os valores na mesma ordem em que GetNames retorna os nomes?" - Este é um ponto muito bom e algo que ainda não falei! Acho que sua primeira solução provavelmente forneceria uma maneira de combinar valores e strings de forma confiável
— TK.

Olá, já vi menção a essa suspeita de "incompatibilidade de índice" ocorrendo ao fazer isso; no entanto, ainda não descobri se isso é realmente uma preocupação ou não? Existem casos definitivos em que essa suposição pode dar errado? THX!
— Funka

Você provavelmente deseja converter o segundo "val" em um int, se quiser solucionar problemas de incompatibilidade de valores, como Enum.GetName(typeof(MyEnum), val), (int)val)em que a saída fornece o nome e o número da enumeração.
— Greg

GetValues ​​e GetNames retornam na mesma ordem, a saber: "Os elementos da matriz de valor de retorno são classificados pelos valores binários das constantes enumeradas (ou seja, por sua magnitude sem sinal)."
— Russell Borogove

Eu acredito que você também pode usar LINQ diretamente chamando Cast<T>o resultado:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
— jocull

33

Você precisa lançar a matriz - a matriz retornada é realmente do tipo solicitado, ou seja, myEnum[]se você solicitar typeof(myEnum):

myEnum[] values = (myEnum[]) Enum.GetValues(typeof(myEnum));

Então values[0]etc


9

Você pode lançar esse Array para diferentes tipos de Arrays:

myEnum[] values = (myEnum[])Enum.GetValues(typeof(myEnum));

ou se você quiser os valores inteiros:

int[] values = (int[])Enum.GetValues(typeof(myEnum));

Você pode iterar essas matrizes lançadas, é claro :)


7

Que tal uma lista de dicionário?

Dictionary<string, int> list = new Dictionary<string, int>();
foreach( var item in Enum.GetNames(typeof(MyEnum)) )
{
    list.Add(item, (int)Enum.Parse(typeof(MyEnum), item));
}

e, claro, você pode alterar o tipo de valor do dicionário para quaisquer valores de enum.


Acho que esse seria o caminho a percorrer, mas infelizmente o enum está em uma área do código sobre a qual não tenho controle!
— TK.

1
A única solução que encontrei que obtém os valores reais de enum inteiro!
— SharpC

5

Outra solução, com possibilidades interessantes:

enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }

static class Helpers
{
public static IEnumerable<Days> AllDays(Days First)
{
  if (First == Days.Monday)
  {
     yield return Days.Monday;
     yield return Days.Tuesday;
     yield return Days.Wednesday;
     yield return Days.Thursday;
     yield return Days.Friday;
     yield return Days.Saturday;
     yield return Days.Sunday;
  } 

  if (First == Days.Saturday)
  {
     yield return Days.Saturday;
     yield return Days.Sunday;
     yield return Days.Monday;
     yield return Days.Tuesday;
     yield return Days.Wednesday;
     yield return Days.Thursday;
     yield return Days.Friday;
  } 
}

4

Aqui está outro. Precisávamos fornecer nomes amigáveis ​​para nossos EnumValues. Usamos System.ComponentModel.DescriptionAttribute para mostrar um valor de string personalizado para cada valor enum.

public static class StaticClass
{
    public static string GetEnumDescription(Enum currentEnum)
    {
        string description = String.Empty;
        DescriptionAttribute da;

        FieldInfo fi = currentEnum.GetType().
                    GetField(currentEnum.ToString());
        da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi,
                    typeof(DescriptionAttribute));
        if (da != null)
            description = da.Description;
        else
            description = currentEnum.ToString();

        return description;
    }

    public static List<string> GetEnumFormattedNames<TEnum>()
    {
        var enumType = typeof(TEnum);
        if (enumType == typeof(Enum))
            throw new ArgumentException("typeof(TEnum) == System.Enum", "TEnum");

        if (!(enumType.IsEnum))
            throw new ArgumentException(String.Format("typeof({0}).IsEnum == false", enumType), "TEnum");

        List<string> formattedNames = new List<string>();
        var list = Enum.GetValues(enumType).OfType<TEnum>().ToList<TEnum>();

        foreach (TEnum item in list)
        {
            formattedNames.Add(GetEnumDescription(item as Enum));
        }

        return formattedNames;
    }
}

Em uso

 public enum TestEnum
 { 
        [Description("Something 1")]
        Dr = 0,
        [Description("Something 2")]
        Mr = 1
 }



    static void Main(string[] args)
    {

        var vals = StaticClass.GetEnumFormattedNames<TestEnum>();
    }

Isso acabará retornando "Algo 1", "Algo 2"


1
Só é bom se as descrições forem estáticas ... se suas descrições precisarem ser alteradas com base em uma instância, essa abordagem não funcionará.
— Llyle 01 de

3

Que tal usar um loop foreach, talvez você pudesse trabalhar com isso?

  int i = 0;
  foreach (var o in values)
  {
    print(names[i], o);
    i++;
  }

algo assim talvez?


Eu aprendi sobre isso ... mas preciso obter acesso a nomes e valores em 'sincronizar' ... digamos que os nomes [2] estejam emparelhados com os valores [2] e não tenho certeza de como fazer isso em um loop foreach!
— TK.

Eu adicionei um exemplo - veja se isso ajuda.
— TWith2Sugars

3

Pergunta antiga, mas uma abordagem um pouco mais limpa usando o LINQ .Cast<>()

var values = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>();

foreach(var val in values)
{
    Console.WriteLine("Member: {0}",val.ToString());     
}


2

Você pode simplificar isso usando strings de formato. Eu uso o seguinte snippet nas mensagens de uso:

writer.WriteLine("Exit codes are a combination of the following:");
foreach (ExitCodes value in Enum.GetValues(typeof(ExitCodes)))
{
    writer.WriteLine("   {0,4:D}: {0:G}", value);
}

O especificador de formato D formata o valor enum como um decimal. Também há um especificador X que fornece saída hexadecimal.

O especificador G formata um enum como uma string. Se o atributo Flags for aplicado ao enum, os valores combinados também serão suportados. Há um especificador F que atua como se Flags estivesse sempre presente.

Veja Enum.Format ().


2

Nos resultados de Enum.GetValues, a conversão para int produz o valor numérico. Usar ToString () produz o nome amigável. Nenhuma outra chamada para Enum.GetName é necessária.

public enum MyEnum
{
    FirstWord,
    SecondWord,
    Another = 5
};

// later in some method  

 StringBuilder sb = new StringBuilder();
 foreach (var val in Enum.GetValues(typeof(MyEnum))) {
   int numberValue = (int)val;
   string friendyName = val.ToString();
   sb.Append("Enum number " + numberValue + " has the name " + friendyName + "\n");
 }
 File.WriteAllText(@"C:\temp\myfile.txt", sb.ToString());

 // Produces the output file contents:
 /*
 Enum number 0 has the name FirstWord
 Enum number 1 has the name SecondWord
 Enum number 5 has the name Another
 */

0

Esta é uma maneira simples de iterar por meio de seu objeto Enum personalizado

For Each enumValue As Integer In [Enum].GetValues(GetType(MyEnum))

     Print([Enum].GetName(GetType(MyEnum), enumValue).ToString)

Next

1
Acho que OP pediu C #.
— jm.

0

Pergunta antiga, mas a resposta do 3Dave forneceu a abordagem mais fácil. Eu precisava de um pequeno método auxiliar para gerar um script Sql para decodificar um valor enum no banco de dados para depuração. Funcionou muito bem:

    public static string EnumToCheater<T>() {
        var sql = "";
        foreach (var enumValue in Enum.GetValues(typeof(T)))
            sql += $@"when {(int) enumValue} then '{enumValue}' ";
        return $@"case ?? {sql}else '??' end,";
    }

Eu tenho um método estático, então o uso é:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
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.