2010-07-01 5 views
25

La méthode statique générique suivante prend une chaîne et renvoie une enum.Comment puis-je tester si une énumération est définie ou non tout en ignorant le cas?

Il joliment ignore le cas depuis que j'ai défini le paramètre ignoreCase sur true.

Cependant, je veux aussi test si le ENUM existe, mais la méthode enum.IsDefined faire cela ne semble pas avoir un paramètre ignoreCase.

Comment puis-je tester si l'énumération est définie ou non et dans le même cas d'ignorance?

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

Vous pouvez envisager une valeur par défaut de None pour vos énumérations. En plus d'être une bonne pratique, telle qu'elle se présente actuellement, si vous passez une chaîne de "Foo" pour l'une ou l'autre de vos énumérations, vous obtenez ce qui semble être des valeurs valides de ConvertStringToEnum. – Marc

Répondre

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

Avec @ réponse de Darin, .NET 4.0, le type Enum a maintenant une méthode TryParse:

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

La chose importante à retenir est qu'il ya une différence fondamentale dans le comportement de Parse vs TryParse. Les méthodes d'analyse jetteront des exceptions. Les méthodes TryParse ne le seront pas. C'est très important de savoir si vous essayez d'analyser de nombreux éléments.

+2

Cela peut renvoyer un résultat inattendu pour les valeurs numériques string'ified. c'est-à-dire 'Enum.TryParse (" 01 ", true, résultat out)' retournera 'true' s'il se trouve qu'il y a une énumération avec la valeur' 1'. D'un autre côté, la réponse de Darin ne correspondra qu'aux noms enum. –

5

Utilisation Enum.TryParse à la place:

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

J'utilise Compact Framework 3.5, et:

Enum.TryParse 

... n'existe pas. Il ne:

Enum.IsDefined 

..mais qui ne supporte pas le paramètre ignoreCase. Je voudrais le meilleur des deux mondes, donc venu avec cette (comme méthode d'assistance) ...

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

Rendre le texte même cas que la chaîne de 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

Vous pourriez être en mesure de s'en tirer en utilisant simplement Enum.TryParse, comme d'autres l'ont dit.

Cependant, si vous voulez une conversion plus robuste/général qui vous permet de convertir plus que des chaînes, alors vous devez aussi utiliser Enum.IsDefined, qui malheureusement, comme vous l'avez trouvé, est pas insensible à la casse.

Enum.TryParseest (peut être) insensible à la casse. Mais malheureusement, il permet de passer à travers des rangs hors-limites! Donc, la solution est de les utiliser ensemble (et la commande est importante).

J'ai écrit une méthode d'extension qui fait exactement cela. Il permet la conversion de chaîne, int/int ?, et tout autre Enum/Enum? tapez comme ceci:

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

est ici au cœur de la méthode. C'est la partie conversion qui répond à votre question. La variable value est de type object en raison des "surcharges" que j'ai qui prennent différents types comme l'entrée principale (voir ci-dessus), mais vous pouvez le faire avec une variable de type string très bien si c'est tout ce que vous voulez (évidemment changer value.ToString() juste 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; 
     } 
    } 
} 

Il y a beaucoup plus à ma méthode d'extension ... il vous permet de spécifier les valeurs par défaut, les poignées hors de portée ints très bien, et est totalement insensible à la casse. Je peux en poster plus si quelqu'un est intéressé.

+1

La clé pour moi était l'idée d'utiliser le résultat de la sortie de TryParse .ToString; Je vous remercie. D'autres qui suggèrent que seulement TryParse manquent les ints hors limites qui peuvent donner des faux positifs. – Syntax

0

J'ai eu une préoccupation similaire et utilisé une combinaison des deux .Enum.TryPase (avec le drapeau insensible à la casse défini comme true) et Enum.IsDefined. Considérez ce qui suit comme une simplification de votre classe d'aide:

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

Et pendant que nous y sommes, puisque la classe d'aide est statique et la méthode est statique - on pourrait en faire une méthode d'extension sur 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); 
    } 
} 

Ici, j'ai créé un .NET Fiddle qui le démontre clairement.

Questions connexes