C # ¿Iterando a través de una enumeración? (Indexación de una matriz de sistema)


113

Tengo el siguiente 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] ); 
}

Sin embargo, no puedo indexar valores. ¿Hay una manera más fácil de hacer esto?

¡O me he perdido algo por completo!

Respuestas:


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

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

O puede convertir el System.Array que se devuelve:

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

Pero, ¿puede estar seguro de que GetValues ​​devuelve los valores en el mismo orden en que GetNames devuelve los nombres?


3
"Pero, ¿puede estar seguro de que GetValues ​​devuelve los valores en el mismo orden en que GetNames devuelve los nombres?" - ¡Este es un punto muy bueno y algo que todavía tengo que abordar! Creo que su primera solución probablemente proporcionaría una forma de hacer coincidir valores y cadenas de manera confiable
TK.

Hola, he visto una mención antes de esta sospecha de "desajuste de índice" que ocurre al hacer esto; sin embargo, todavía tengo que descubrir si esto realmente es una preocupación o no. ¿Existen casos definitivos en los que esta suposición pueda salir mal? ¡Gracias!
Funka

Probablemente desee convertir el segundo "val" en un int, si desea solucionar la falta de coincidencia de valores, como en el caso Enum.GetName(typeof(MyEnum), val), (int)val)de que la salida proporcione el nombre y el número de enumeración.
Greg

GetValues ​​y GetNames regresan en el mismo orden, a saber: "Los elementos de la matriz de valor de retorno se ordenan por los valores binarios de las constantes enumeradas (es decir, por su magnitud sin signo)".
Russell Borogove

Creo que también puede usar LINQ directamente llamando Cast<T>al resultado:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
jocull

33

Debe convertir la matriz; la matriz devuelta es en realidad del tipo solicitado, es decir, myEnum[]si solicita typeof(myEnum):

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

Entonces, values[0]etc.


9

Puede convertir esa matriz a diferentes tipos de matrices:

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

o si quieres los valores enteros:

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

Puede iterar esas matrices fundidas, por supuesto :)


7

¿Qué tal una lista de diccionarios?

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

y, por supuesto, puede cambiar el tipo de valor del diccionario a cualquiera que sea su enumeración.


Creo que este sería el camino a seguir, ¡pero desafortunadamente la enumeración está en un área de código sobre la que no tengo control!
TK.

1
¡La única solución que he encontrado que obtiene los valores de enumeración enteros reales!
SharpC

5

Otra solución, con interesantes posibilidades:

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

Aquí está otro. Tuvimos la necesidad de proporcionar nombres descriptivos para nuestros EnumValues. Usamos System.ComponentModel.DescriptionAttribute para mostrar un valor de cadena personalizado para cada valor de enumeración.

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

En uso

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



    static void Main(string[] args)
    {

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

Esto terminará mostrando "Algo 1", "Algo 2"


1
Solo es bueno si las descripciones son estáticas ... si sus descripciones deben cambiar en función de una instancia, este enfoque no funcionará.
Llyle

3

¿Qué hay de usar un bucle foreach, tal vez podrías trabajar con eso?

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

tal vez algo así?


Tengo algo de eso ... pero necesito tener acceso tanto a los nombres como a los valores en 'sincronización' ... digamos que los nombres [2] están emparejados con los valores [2] y no estoy seguro de cómo lograr esto en un bucle foreach!
TK.

Agregué un ejemplo, vea si eso ayuda.
TWith2Sugars

3

Pregunta antigua, pero un enfoque un poco más limpio con LINQ .Cast<>()

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

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


2

Puede simplificar esto usando cadenas de formato. Utilizo el siguiente fragmento en los mensajes 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);
}

El especificador de formato D formatea el valor de enumeración como decimal. También hay un especificador X que proporciona una salida hexadecimal.

El especificador G formatea una enumeración como una cadena. Si el atributo Flags se aplica a la enumeración, también se admiten los valores combinados. Hay un especificador F que actúa como si Flags estuviera siempre presente.

Consulte Enum.Format ().


2

En los resultados de Enum.GetValues, la conversión a int produce el valor numérico. El uso de ToString () produce el nombre descriptivo. No se necesitan otras llamadas a Enum.GetName.

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

Aquí hay una forma sencilla de iterar a través de su objeto Enum personalizado

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

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

Next

1
Creo que OP pidió C #.
jm.

0

Pregunta antigua, pero la respuesta de 3Dave proporcionó el enfoque más fácil. Necesitaba un pequeño método auxiliar para generar un script Sql para decodificar un valor de enumeración en la base de datos para la depuración. Funcionó muy bien:

    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,";
    }

Lo tengo en un método estático, por lo que el uso es:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.