2009-09-15 12 views
16

que tiene un tipo de enumeración como esto como un ejemplo:analizar la cadena de enumeración de tipo

public Enum MyEnum { 
    enum1, enum2, enum3 }; 

Voy a leer una cadena desde el archivo de configuración. Lo que necesito para analizar la cadena al tipo MyEnum o nulo o no definido. No estoy seguro si los siguientes códigos funcionarán (lo siento por no tener acceso a mi VS en este momento):

// example: ParseEnum<MyEnum>("ENUM1", ref eVal); 
bool ParseEnum<T>(string value1, ref eVal) where T : Enum 
{ 
    bool bRet = false; 
    var x = from x in Enum.GetNames(typeof(T)) where 
     string.Equals(value1, x, StringComparison. OrdinalIgnoreCase) 
     select x; 
    if (x.Count() == 1) 
    { 
    eVal = Enum.Parse(typeof(T), x.Item(0)) as T; 
    bRet = true; 
    } 
    return bRet; 
} 

no está seguro de si es correcto o hay alguna otra forma sencilla de analizar una cadena de valor MyEnum?

+0

Salida Enum.TryParse, como se menciona en [este mensaje] (http://www.codeducky.org/ins- outs-c-enums /). – ChaseMedallion

Respuesta

31

¿Qué pasa algo como:

public static class EnumUtils 
{ 
    public static Nullable<T> Parse<T>(string input) where T : struct 
    { 
     //since we cant do a generic type constraint 
     if (!typeof(T).IsEnum) 
     { 
      throw new ArgumentException("Generic Type 'T' must be an Enum"); 
     } 
     if (!string.IsNullOrEmpty(input)) 
     { 
      if (Enum.GetNames(typeof(T)).Any(
        e => e.Trim().ToUpperInvariant() == input.Trim().ToUpperInvariant())) 
      { 
       return (T)Enum.Parse(typeof(T), input, true); 
      } 
     } 
     return null; 
    } 
} 

Se utiliza como:

MyEnum? value = EnumUtils.Parse<MyEnum>("foo"); 

(Nota: versión antigua utiliza try/catch alrededor Enum.Parse)

+1

No es una buena idea usar el manejo de excepciones en el flujo de programa normal ... –

+1

@Mark Lo sé, pero es seguro en casos como este :) –

+0

@ Mark hace un buen punto - try/catch rara vez es bueno idea. La versión editada es considerablemente más eficiente que la de la pregunta, ya que solo hace una enumeración parcial en lugar de hasta 3 ish. –

5
private enum MyEnum 
{ 
    Enum1 = 1, Enum2 = 2, Enum3 = 3, Enum4 = 4, Enum5 = 5, Enum6 = 6, 
    Enum7 = 7, Enum8 = 8, Enum9 = 9, Enum10 = 10 
} 

private static Object ParseEnum<T>(string s) 
{ 
    try 
    { 
     var o = Enum.Parse(typeof (T), s); 
     return (T)o; 
    } 
    catch(ArgumentException) 
    { 
     return null; 
    } 
} 

static void Main(string[] args) 
{ 
    Console.WriteLine(ParseEnum<MyEnum>("Enum11")); 
    Console.WriteLine(ParseEnum<MyEnum>("Enum1")); 
    Console.WriteLine(ParseEnum<MyEnum>("Enum6").GetType()); 
    Console.WriteLine(ParseEnum<MyEnum>("Enum10")); 
} 

SALIDA:

//This line is empty as Enum11 is not there and function returns a null 
Enum1 
TestApp.Program+MyEnum 
Enum10 
Press any key to continue . . . 
2

Si está utilizando .NET 3.5 (o incluso 2.0, si recorta a cabo el método de extensión), he tenido mucha suerte con las técnicas descritas en este artículo:

enumeraciones y Cuerdas - detener la locura !

EDITAR: El dominio se ha ido y ahora es una granja de enlaces. Me sacó el código (ligeramente modificado y se añade a lo largo del tiempo) de nuestra base de código en el trabajo, que ahora se puede encontrar aquí:

https://gist.github.com/1305566

+2

La referencia ahora apunta a una granja de enlaces. Inicialmente te modifiqué uno, pero eres bastante alto representante, así que supongo que no estás haciendo esto intencionalmente, y no deberías ser penalizado por lo que sucede con el contenido fuera de tu control. Busqué el artículo yo mismo pero no di con nada obvio. ¿Puedes ver si hay un mejor enlace para este contenido? –

+0

@MichaelBlackburn: Parece que el tipo que tenía el dominio desapareció. Comprobaré en nuestra base de código el lunes y veré si puedo encontrar lo que pedí prestado del artículo. –

2

tengo un método TryParseName en UnconstrainedMelody, una biblioteca para delegar y enumeración de utilidad métodos que usan restricciones "inexpresables" a través de algunos trucos postconstrucción. (Código utilizando la biblioteca no necesita un postbuild, para ser claros.)

que usaría así:

Foo foo; 
bool parsed = Enums.TryParseName<Foo>(name, out foo); 

no tiene actualmente una versión de mayúsculas y minúsculas, pero podría presentar uno fácilmente si quisiera. Tenga en cuenta que no intenta intentar analizar números, p. "12" como lo hace la versión incorporada, ni intenta analizar listas de banderas separadas por comas. Puedo agregar la versión de indicadores más adelante, pero no veo mucho sentido en la versión numérica.

Esto se hace sin boxeo y sin verificación del tipo de tiempo de ejecución. Tener la restricción es realmente útil :)

Por favor, hágamelo saber si iba a encontrar un análisis sintáctico entre mayúsculas y minúsculas útil ...

+0

@Jon Skeet, puede introducir un método adicional sobrecargado para que el usuario tenga opciones de mayúsculas y minúsculas o no. –

+0

@Joh Skeet, no estoy seguro si su método debe ser (nombre, refiérase a foo) o no. Si tryparse falla, ¿qué debería ser? El primer valor enum? Creo que es mejor dejar que el usuario lo inicialice y no lo cambie si falla. Entiendo que trates de hacer que este método sea consistente con TryParse (nombre, valor de salida). –

+1

Si 'TryParse' falla, será' default (Foo) 'que es consistente con' TryParse', 'TryGetValue', etc. Si no fuera por la coherencia, probablemente devolvería un' Nullable 'en su lugar. Examinaré la introducción de una nueva sobrecarga para la coincidencia de mayúsculas y minúsculas o, posiblemente, la de un StringComparer (o similar) para permitir que también se seleccione la sensibilidad cultural. –

1

Acabo combinado la sintaxis de here, con el manejo de here excepción, para crear esta:

public static class Enum<T> 
{ 
    public static T Parse(string value) 
    { 
     //Null check 
     if(value == null) throw new ArgumentNullException("value"); 
     //Empty string check 
     value = value.Trim(); 
     if(value.Length == 0) throw new ArgumentException("Must specify valid information for parsing in the string", "value"); 
     //Not enum check 
     Type t = typeof(T); 
     if(!t.IsEnum) throw new ArgumentException("Type provided must be an Enum", "TEnum"); 

     return (T)Enum.Parse(typeof(T), value); 
    } 
} 

se podría girar un poco para devolver null en lugar de lanzar excepciones.

+0

@Benjol, me gusta el uso de type.IsEnum para verificar su tipo. –

1

Puede usar TryParse si desea evitar el uso de try/catch.

MyEnum eVal; 
if (Enum.TryParse("ENUM2", true, out eVal)){ 
    // now eVal is the enumeration element: enum2 
} 
//unable to parse. You can log the error, exit, redirect, etc... 

Modifiqué un poco la respuesta seleccionada. Espero que te guste.

public static class EnumUtils 
{ 
    public static Nullable<T> Parse<T>(string input) where T : struct 
    { 
     //since we cant do a generic type constraint 
     if (!typeof(T).IsEnum) 
     { 
      throw new ArgumentException("Generic Type 'T' must be an Enum"); 
     } 

     int intVal; 
     if (!string.IsNullOrEmpty(input) && !int.TryParse(input, out intVal)) 
     { 
      T eVal; 
      if (Enum.TryParse(input, true, out eVal)) 
      { 
       return eVal; 
      } 
     } 
     return null; 
    } 
} 
0

Para volver Enum por la cadena, si contiene:

public static T GetEnum<T>(string s) 
    { 
     Array arr = Enum.GetValues(typeof(T)); 
     foreach (var x in arr) 
     { 
      if (x.ToString().Contains(s)) 
       return (T)x; 
     } 
     return default(T); 
    }