2012-09-16 7 views
5

dado una enumeración de esta manera:¿Cómo puedo usar Generics para crear una forma de hacer un IEnumerable a partir de una enumeración?

public enum City { 
    London = 1, 
    Liverpool = 20, 
    Leeds  = 25 
} 

public enum House { 
    OneFloor = 1, 
    TwoFloors = 2 
} 

Estoy utilizando el código siguiente para darme un IEnumerable:

City[] values = (City[])Enum.GetValues(typeof(City)); 
var valuesWithNames = from value in values      
    select new { value = (int)value, name = value.ToString() }; 

El código funciona muy bien, sin embargo tengo que hacer esto desde hace mucho enums. ¿Hay alguna manera de que yo pueda crear una forma genérica de hacer esto?

+1

El problema es que C# no permite las restricciones 'enum' en los tipos genéricos. Puede usar la [melodía no restringida] de Jon Skeet (http://code.google.com/p/unconstrained-melody/). – Adam

+0

Si necesita el 'IEnumerable' solo en tiempo de ejecución, puede usar el reflejo. De lo contrario, puede considerar usar [plantilla] (http://msdn.microsoft.com/en-us/library/bb126445.aspx) Y reflejo. – Guillaume

Respuesta

1

Esta función puede ayudarle a:

public static IEnumerable<KeyValuePair<int, string>> GetValues<T>() where T : struct 
{ 
     var t = typeof(T); 
     if(!t.IsEnum) 
      throw new ArgumentException("Not an enum type"); 

     return Enum.GetValues(t).Cast<T>().Select (x => 
       new KeyValuePair<int, string>(
        (int)Enum.ToObject(t, x), 
        x.ToString())); 
} 

Uso:

var values = GetValues<City>(); 
+0

'InvalidOperationException' se define como *" La excepción que se produce cuando una llamada de método no es válida para el estado actual del objeto."* Parece una excepción realmente engañosa. – Adam

+0

@codesparkle Quizás. Lo cambié a' ArgumentException' – Magnus

+0

Una 'TypeArgumentException' como la definida en * UnconstrainedMelody * sería ideal. La excepción predefinida más adecuada es probablemente 'ArgumentException' though * (" La excepción que se lanza cuando uno de los argumentos proporcionados a un método no es válido. ") * – Adam

1

Por qué no:

IEnumerable<object> GetValues<T>() 
    { 
     return Enum.GetValues(typeof (T)) 
        .Cast<T>() 
        .Select(value => new {  
              value = Convert.ToInt32(value), 
              name = value.ToString() 
             }); 

    } 

lo que puede utilizar:

var result = GetValues<City>(); 

Si desea hacer limitación genérica T como enum, porque enumno se puede utilizar como contraint genérica directamente, pero enum hereda de la interfaz IConvertible, cree que esta manera está bien:

IEnumerable<object> GetValues<T>() where T: struct, IConvertible 
{} 

Para reemplazar IEnumerable<object> por Dictionary:

Dictionary<int, string> GetValues<T>() where T : struct, IConvertible 
{ 
    return Enum.GetValues(typeof (T)).Cast<T>() 
       .ToDictionary(value => Convert.ToInt32(value), 
          value => value.ToString()); 
} 

Editar: Como comentario de Magnus, si es necesario asegurarse de que el orden de los elementos, diccionario no es la opción. Definir tu propio tipo fuerte sería mejor.

+0

Veo dos problemas al devolver un diccionario: primero está desordenado. En segundo lugar, parece innecesario devolver un diccionario si no se va a utilizar para la búsqueda. – Magnus

+0

@Magnus: cierto con desordenado, por lo que uso es Diccionario es más fuerte que IEmmerable . –

3

de unconstrained melody Uso Jon Skeet.

using UnconstrainedMelody; 

Usted puede poner sus valores de enumeración en un Dictionary<int, string> y luego enumerar sobre ellos:

var valuesAsDictionary = Enums.GetValues<City>() 
           .ToDictionary(key => (int)key, value => value.ToString()); 

Pero es probable que ni siquiera necesita hacer eso. ¿Por qué no simplemente enumerar los valores directamente?

foreach (var value in Enums.GetValues<City>()) 
{ 
    Console.WriteLine("{0}: {1}", (int)value, value); 
} 
+0

¿Por qué está lanzando a' int' y no a 'T'? Los enums no tienen que ser ints , y no hay ninguna razón por la que no pueda devolver un 'Diccionario ' en su lugar. – Lee

+1

@Lee En la pregunta explícitamente quiere int y string. – Magnus

+0

@Lee pero, nuevamente, ¿para qué crear un diccionario cuando toda la información que necesita existe? dentro del valor enum en sí mismo? Este es el punto que traté de expresar en la segunda mitad de mi respuesta. – Adam

Cuestiones relacionadas