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.