2009-09-15 12 views
16

Ich habe einen Aufzählungstyp wie dies als Beispiel:Parse String Aufzählungstyp

public Enum MyEnum { 
    enum1, enum2, enum3 }; 

Ich werde eine Reihe von Konfigurationsdatei lesen. Was ich brauche, um die Zeichenfolge zu MyEnum-Typ oder Null zu analysieren o nicht definiert. Nicht sicher, ob die folgenden Codes funktionieren (sorry für nicht jetzt Zugriff auf meinen VS hat):

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

nicht sicher, ob es richtig ist, oder gibt es andere einfache Möglichkeit, eine Zeichenfolge zu MyEnum Wert zu analysieren?

+0

Check out Enum.TryParse, wie erwähnt in [diesem Beitrag] (http://www.codeducky.org/ins- outs-c-enums /). – ChaseMedallion

Antwort

31

Was ist so etwas wie:

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

als:

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

(Hinweis: alte Version try/catch um Enum.Parse verwendet)

+1

Es ist keine gute Idee, die Ausnahmebehandlung im normalen Programmablauf zu verwenden ... –

+1

@Mark Ich weiß, aber es ist einfach in solchen Fällen :) –

+0

@Mark macht einen guten Punkt - versuchen/fangen ist selten ein gutes Idee. Die bearbeitete Version ist wesentlich effizienter als die in der Frage, da sie nur eine partielle Aufzählung statt bis zu 3-ish durchführt. –

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

OUTPUT:

2

Wenn Sie .NET 3.5 (oder sogar 2,0, wenn Sie die Erweiterung Methode trimmen), habe ich in diesem Artikel mit den Techniken großes Glück hatte:

Aufzählungen und Streicher - Stoppen Sie den Wahnsinn !

EDIT: Domain ist weg und ist jetzt eine Linkfarm. Ich zog den Code (leicht modifizierte und hinzugefügt, um im Laufe der Zeit) von unserer Code-Basis bei der Arbeit, die Sie jetzt hier finden:

https://gist.github.com/1305566

+2

Referenz verweist jetzt auf eine Verknüpfungsfarm. Ich habe dich anfangs um eine modifiziert, aber du bist ziemlich hochrangig, also schätze ich, dass du das nicht absichtlich tust, und du solltest nicht dafür bestraft werden, was mit Inhalten passiert, die du nicht kontrollierst. Ich habe selbst nach dem Artikel gesucht, aber nichts Offensichtliches gemacht. Kannst du sehen, ob es einen besseren Link für diesen Inhalt gibt? –

+0

@MichaelBlackburn: Sieht so aus, als ob der Typ, der die Domain hatte, verschwunden ist. Ich werde Montag in unserer Codebase einchecken und sehen, ob ich finden kann, was ich aus dem Artikel geliehen habe. –

2

Ich habe eine TryParseName Methode in UnconstrainedMelody, eine Bibliothek für die Delegierten und Enum-Dienstprogramm Methoden, die "unaussprechliche" Constraints über einige Postbuild-Tricks verwenden. (Code- mit der Bibliothek keine postbuild brauchen, um nur klar zu sein.)

Sie würde es so verwenden:

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

ich derzeit keine Groß- und Kleinschreibung Version haben, aber ich könnte es leicht einführen, wenn du wolltest. Beachten Sie, dass nicht versucht, Zahlen zu analysieren, z. "12" wie die integrierte Version, und versucht auch nicht, durch Kommas getrennte Listen von Flags zu analysieren. Ich kann die Flaggenversion später hinzufügen, aber ich kann nicht viel Punkt in der numerischen Version sehen.

Dies geschieht ohne Boxing und ohne Überprüfung der Ausführungszeit. die Einschränkung zu haben, ist wirklich praktisch :)

Bitte lassen Sie mich wissen, wenn Sie sinnvoll, ein Groß- und Kleinschreibung Parse finden würde ...

+0

@ Jon Skeet, können Sie eine zusätzliche überladene Methode einführen, um dem Benutzer die Wahl zwischen Groß- und Kleinschreibung zu ermöglichen. –

+0

@Joh Skeet, nicht sicher, ob Ihre Methode (Name, Ref foo) sein sollte oder nicht. Wenn tryparse fehlschlägt, was sollte foo sein? Der erste Aufzählungswert? Ich denke, es ist besser, wenn der Benutzer es initialisiert und nicht ändert, wenn es nicht funktioniert. Ich verstehe, dass Sie versuchen, diese Methode mit TryParse (Name, out-Wert) konsistent zu machen. –

+1

Wenn 'TryParse' fehlschlägt, wird' default (Foo) ', was mit' TryParse', 'TryGetValue' etc. übereinstimmt. Wenn ich nicht auf Konsistenz bedacht wäre, würde ich wahrscheinlich stattdessen eine' Nullable ' zurückgeben. Ich werde versuchen, eine neue Überladung für die Unterscheidung zwischen Groß- und Kleinschreibung einzuführen - oder möglicherweise einen StringComparer (oder ähnlich) zu verwenden, um auch kulturelle Sensibilität zuzulassen. –

1

ich nur die Syntax von here, mit Ausnahme von here Handhabung kombiniert haben, diese zu erstellen:

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

Sie es ein bisschen drehen könnte null statt werfen Ausnahmen zurückzukehren.

+0

@Benjol, Ich mag Ihre Verwendung type.IsEnum, um seinen Typ zu überprüfen. –

1

Sie können TryParse verwenden, wenn Sie try/catch vermeiden möchten.

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... 

Ich modifizierte die ausgewählte Antwort ein wenig. Ich hoffe du magst es.

0

Enum Rückkehr von string, wenn enthält:

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