2010-07-01 19 views
25

Il seguente metodo statico generico prende una stringa e restituisce un valore enum.Come posso verificare se un enum è definito o meno ignorando il caso?

E 'ben ignora il caso poiché ho impostato il parametro ignoreCase su true.

Tuttavia, voglio anche prova se l'enum esiste, ma il metodo enum.IsDefined per fare questo non sembra avere un parametro ignoreCase.

Come posso verificare se l'enumerazione è definita o meno e nello stesso caso ignorato?

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

È possibile considerare un valore predefinito di Nessuno per le enumerazioni. Oltre ad essere una buona pratica, così com'è ora, se passi una stringa di "Foo" per una delle tue enumerazioni, ottieni ciò che sembra essere un valore valido da ConvertStringToEnum. – Marc

risposta

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

Insieme con @ risposta di Darin, in .NET 4.0, il tipo Enum ha ora un metodo TryParse:

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

La cosa importante da ricordare è che c'è una differenza fondamentale nel comportamento di Parse vs TryParse. I metodi Parse generano eccezioni. I metodi TryParse non lo faranno. Questo è abbastanza importante sapere se si sta tentando potenzialmente di analizzare molti articoli.

+2

Ciò potrebbe restituire un risultato imprevisto per valori numerici definiti da stringa. Ad esempio, 'Enum.TryParse (" 01 ", true, out result)' restituirà 'true' se vi è un'enum con il valore' 1'. D'altra parte, la risposta di Darin corrisponderà solo ai nomi enum. –

5

Uso Enum.TryParse invece:

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

sto usando Compact Framework 3.5, e:

Enum.TryParse 

... non esiste. Essa ha ancora:

Enum.IsDefined 

..ma che non supporta il parametro ignoreCase. vorrei il meglio dei due mondi, così si avvicinò con questo (come un metodo di supporto) ...

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

la dimensione del testo stesso caso come stringa enum:

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

Si potrebbe essere in grado di cavarsela semplicemente usando Enum.TryParse, come altri hanno già detto.

Tuttavia, se si desidera un più robusto conversione/generale che permette di convertire più di un semplice stringhe, allora avete bisogno di utilizzare anche Enum.IsDefined, che purtroppo, come l'avete trovato, è non maiuscole e minuscole.

Enum.TryParseè (può essere) case-insensitive. Ma sfortunatamente, permette di superare gli out-of-range inte!

Quindi la soluzione è usarli insieme (e l'ordine è importante).

Ho scritto un metodo di estensione che fa proprio questo. Permette la conversione da string, int/int? E qualsiasi altro Enum/Enum? digitare in questo modo:

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

Ecco il cuore del metodo. Questa è la parte di conversione che risponde alla tua domanda. La variabile value è di tipo object a causa degli "overload" che ho che prendono tipi diversi come input principale (vedi sopra), ma puoi farlo con una variabile di tipo string bene se è tutto ciò che vuoi (ovviamente 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; 
     } 
    } 
} 

C'è molto di più per il mio metodo di estensione ... Esso consente di specificare le impostazioni predefinite, maniglie out-of-range int bene, ed è completamente maiuscole e minuscole. Posso pubblicarne altri se qualcuno è interessato.

+1

La chiave per me è stata l'idea di utilizzare il risultato dell'output di TryParse .ToString; grazie. Altri che suggeriscono solo TryParse perdono gli intintori fuori intervallo che possono dare corrispondenze false positive. – Syntax

0

Avevo un problema simile e ho utilizzato una combinazione di entrambi i .Enum.TryPase (con il flag senza distinzione tra maiuscole e minuscole impostato come true) e Enum.IsDefined. Si consideri il seguente come una semplificazione alla classe helper:

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

E già che ci siamo, dal momento che la classe di supporto è statico e il metodo è statico - potremmo fare questo metodo una proroga 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); 
    } 
} 

Qui, ho creato un .NET Fiddle che dimostra chiaramente questo.

Problemi correlati