2010-07-01 16 views
25

El siguiente método genérico estático toma cadena y devuelve enumeración.¿Cómo puedo verificar si una enumeración está definida o no mientras ignoro el caso?

Es muy bueno ignora el caso ya que establecí el parámetro ignoreCase en verdadero.

Sin embargo, también quiero prueba si existe la enumeración, pero no parece el método enum.IsDefined hacer esto para tener un parámetro deignoreCase.

¿Cómo puedo comprobar si la enumeración está definida o no y, al mismo tiempo, ignorar el caso?

using System; 

namespace TestEnum2934234 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      LessonStatus lessonStatus = StringHelpers.ConvertStringToEnum<LessonStatus>("prepared"); 
      ReportStatus reportStatus = StringHelpers.ConvertStringToEnum<ReportStatus>("finished"); 

      Console.WriteLine(lessonStatus.ToString()); 
      Console.WriteLine(reportStatus.ToString()); 
      Console.ReadLine(); 
     } 
    } 

    public static class StringHelpers 
    { 
     public static T ConvertStringToEnum<T>(string text) 
     { 
      if (Enum.IsDefined(typeof(T), text)) //does not have ignoreCase parameter 
       return (T)Enum.Parse(typeof(T), text, true); 
      else 
       return default(T); 
     } 
    } 

    public enum LessonStatus 
    { 
     Defined, 
     Prepared, 
     Practiced, 
     Recorded 
    } 

    public enum ReportStatus 
    { 
     Draft, 
     Revising, 
     Finished 
    } 
} 
+3

Es posible que desee considerar un valor predeterminado de Ninguno para sus enumeraciones. Además de ser una buena práctica, tal como está ahora, si pasas una cadena de "Foo" para cualquiera de tus enums, obtienes lo que parecen ser valores válidos de ConvertStringToEnum. – Marc

Respuesta

30
public enum MyEnum 
{ 
    Bar, 
    Foo 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var containsFoo = Enum.GetNames(typeof(MyEnum)).Any(x => x.ToLower() == "foo"); 
     Console.WriteLine(containsFoo); 
    } 
} 
27

Junto con @ respuesta de Darin, en .NET 4.0, el tipo de enumeración tiene ahora un método TryParse:

MyEnum result; 
Enum.TryParse("bar", true, out result); 

Lo importante para recordar es que hay una diferencia fundamental en el comportamiento de Parse vs TryParse. Los métodos de Parse arrojarán excepciones. Los métodos TryParse no lo harán. Esto es bastante importante para saber si potencialmente está tratando de analizar muchos elementos.

+2

Esto puede devolver un resultado inesperado para los valores numéricos de cadena. es decir, 'Enum.TryParse (" 01 ", true, out result)' devolverá 'true' si sucede que hay una enumeración con el valor' 1'. Por otro lado, la respuesta de Darin solo coincidirá con los nombres enum. –

5

Uso Enum.TryParse lugar:

T val; 

if(Enum.TryParse(text, true, out val)) 
    return val; 
else 
    return default(T); 
0
public static T ConvertStringToEnum<T>(string text) 
{ 
    T returnVal; 
    try 
    { 
     returnVal = (T) Enum.Parse(typeof(T), text, true); 
    } 
    catch(ArgumentException) 
    { 
     returnVal = default(T); 
    } 
    return returnVal; 
} 
1
enum DaysCollection 
    { 
    sunday, 
    Monday, 
    Tuesday, 
    Wednesday, 
    Thursday, 
    Friday, 
    Saturday 
    } 

    public bool isDefined(string[] arr,object obj) 
    { 
     bool result=false; 
     foreach (string enu in arr) 
     { 
       result = string.Compare(enu, obj.ToString(), true) == 0; 
       if (result) 
        break; 

     } 
     return result; 


    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     object obj = "wednesday"; 
     string[] arr = Enum.GetNames(typeof(DaysCollection)).ToArray(); 

     isDefined(arr,obj); 
    } 
6

estoy usando Compact Framework 3.5, y:

Enum.TryParse 

... no existe. Se tiene:

Enum.IsDefined 

..pero que no admite el parámetro ignoreCase. me gustaría lo mejor de ambos mundos, por lo que se le ocurrió esto (como un método de ayuda) ...

public bool TryParse<TEnum>(string value, bool ignoreCase, ref TEnum result) where TEnum : struct 
{ 
    bool parsed; 
    try 
    { 
     result = (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase); 
     parsed = true; 
    } 
    catch { } 
    return parsed; 
} 

HTH

0

Haga texto mismo caso que la cadena de enumeración:

enum FileExts 
{ 
    jpg, 
    pdf 
} 

if (Enum.IsDefined(typeof(T), text.tolower())) //does not have ignoreCase parameter 
    return (T)Enum.Parse(typeof(T), text, true); 
else 
    return default(T); 
3

Es posible que pueda salirse con la suya simplemente usando Enum.TryParse, como han dicho otros.

Sin embargo, si desea una conversión más robusto/en general que le permite convertir más que cuerdas, entonces es necesario también utilizar Enum.IsDefined, que por desgracia, como lo encontró, es no entre mayúsculas y minúsculas.

Enum.TryParsees (puede ser) mayúsculas y minúsculas. ¡Pero desafortunadamente, permite que los fuera de rango pasen!

Así que la solución es usarlos juntos (y el orden es importante).

Escribí un método de extensión que hace precisamente eso. ¿Permite la conversión de cadena, int/int ?, y cualquier otro Enum/Enum? escriba así:

string value1 = "Value1"; 
Enum2 enum2 = value1.ParseToEnum<Enum2>(); 
Debug.Assert(enum2.ToString() == value1); 

Enum1 enum1 = Enum1.Value1; 
enum2 = enum1.ParseToEnum<Enum2>(); 
Debug.Assert(enum2.ToString() == enum1.ToString()); 

int value2 = 1; 
enum2 = value2.ParseToEnum<Enum2>(); 
Debug.Assert(enum2.GetHashCode() == value2); 

Aquí está el corazón del método. Esta es la parte de conversión que responde su pregunta. La variable value es del tipo object debido a las "sobrecargas" que tengo que toman diferentes tipos como la entrada principal (ver arriba), pero puedes hacerlo con una variable de tipo string bien si eso es todo lo que quieres (obviamente cambiando value.ToString() a solo value).

if (value != null) 
{ 
    TEnum result; 
    if (Enum.TryParse(value.ToString(), true, out result)) 
    { 
     // since an out-of-range int can be cast to TEnum, double-check that result is valid 
     if (Enum.IsDefined(typeof(TEnum), result.ToString())) 
     { 
      return result; 
     } 
    } 
} 

Hay mucho más a mi método de extensión ... que le permite especificar valores predeterminados, maneja enteros fuera de rango muy bien, y es totalmente sensible a las mayúsculas. Puedo publicar más si alguien está interesado.

+1

La clave para mí fue la idea de usar el resultado de la salida de TryParse .ToString; gracias. Otros que sugieren solo TryParse se pierden las entradas fuera de rango que pueden dar coincidencias falsas positivas. – Syntax

0

Tuve un problema similar y utilicé una combinación de .Enum.TryPase (con el indicador de mayúsculas y minúsculas establecido como true) y Enum.IsDefined. Considere lo siguiente como una simplificación de su clase de ayuda:

public static class StringHelpers 
{ 
    public static T ConvertStringToEnum<T>(string text) 
    { 
     T result; 
     return Enum.TryParse(text, true, out result) 
      && Enum.IsDefined(result.ToString()) 
       ? result 
       : default(T); 
    } 
} 

Y ya que estamos en ello, ya que la clase de ayuda es estático y el método es estático - podríamos hacer este método una extensión en string.

public static class StringExtensions 
{ 
    public static TEnum ToEnum<TEnum>(this string text) 
     where TEnum : struct, IComparable, IFormattable, IConvertible 
    { 
     TEnum result = default(TEnum); 
     return !string.IsNullOrWhiteSpace(text) 
      && Enum.TryParse(text, true, out result) 
      && Enum.IsDefined(typeof(TEnum), result.ToString()) 
       ? result 
       : default(TEnum); 
    } 
} 

Aquí, he creado un .NET Fiddle que demuestra claramente.

Cuestiones relacionadas