2009-06-23 18 views
4

Ich habe eine ENUM stellvertretend für alle Materialverbunde Codes im System:Wie kann ich einen enum Wert von seiner Beschreibung erhalten?

public enum EAssemblyUnit 
{ 
    [Description("UCAL1")] 
    eUCAL1, 
    [Description("UCAL1-3CP")] 
    eUCAL13CP, 
    [Description("UCAL40-3CP")] 
    eUCAL403CP, // ... 
} 

In Legacy-Code in einem anderen Teil des Systems, ich habe mit Strings markierte Objekte, die die ENUM-Beschreibungen entsprechen. Wenn man einen dieser Strings erhält, was ist der sauberste Weg, um den Enum-Wert zu erhalten? Ich sehe so etwas wie:

public EAssemblyUnit FromDescription(string AU) 
{ 
    EAssemblyUnit eAU = <value we find with description matching AU> 
    return eAU; 
} 

Antwort

8

Sie müssen durch all statischen Felder der Enumeration iterieren (das ist, wie sie in der Reflexion gespeichert sind) für jeden die Beschreibung Attribut zu finden ... wenn Sie das vor Ort Richtig, erhalte den Wert des Feldes.

Zum Beispiel: (. Dies ist nur allgemeine, um es für verschiedene Aufzählungen wiederverwendbar zu machen)

public static T GetValue<T>(string description) 
{ 
    foreach (var field in typeof(T).GetFields()) 
    { 
     var descriptions = (DescriptionAttribute[]) 
       field.GetCustomAttributes(typeof(DescriptionAttribute), false); 
     if (descriptions.Any(x => x.Description == description)) 
     { 
      return (T) field.GetValue(null); 
     } 
    } 
    throw new SomeException("Description not found"); 
} 

Offensichtlich würden Sie die Beschreibungen cachen, wenn Sie dies sogar etwas häufiger tun zB:

public static class DescriptionDictionary<T> where T : struct 
{ 
    private static readonly Dictionary<string, T> Map = 
     new Dictionary<string, T>(); 

    static DescriptionDictionary() 
    { 
     if (typeof(T).BaseType != typeof(Enum)) 
     { 
      throw new ArgumentException("Must only use with enums"); 
     } 
     // Could do this with a LINQ query, admittedly... 
     foreach (var field in typeof(T).GetFields 
       (BindingFlags.Public | BindingFlags.Static)) 
     { 
      T value = (T) field.GetValue(null); 
      foreach (var description in (DescriptionAttribute[]) 
       field.GetCustomAttributes(typeof(DescriptionAttribute), false)) 
      { 
       // TODO: Decide what to do if a description comes up 
       // more than once 
       Map[description.Description] = value; 
      } 
     } 
    } 

    public static T GetValue(string description) 
    { 
     T ret; 
     if (Map.TryGetValue(description, out ret)) 
     { 
      return ret; 
     } 
     throw new WhateverException("Description not found"); 
    } 
} 
+1

Ugh, hoffte wirklich "hier ist eine praktische Funktion, die sich wie ein Wörterbuch <> zwischen Beschreibung und Wert verhält". Vielleicht werde ich eine Klasse erstellen, die dieses Wörterbuch statisch enthält und es füllt, wenn es das erste Mal benötigt wird ...? –

+0

Ja - das Kernbit, das du brauchst, ist das Bit meiner Antwort, das die Beschreibung gibt. Oh stopf es ... Ich werde es jetzt schreiben. Bleib dran :) –

+0

Ja, das habe ich mir gedacht, aber ich werde froh sein, Code von Jon Skeet in 5 Minuten über das zu schreiben, woran ich mich wahrscheinlich in mehr als einer Stunde schreiben würde. Geprüft. Klappt wunderbar. –

0
public EAssemblyUnit FromDescription(string AU) 
{ 
    EAssemblyUnit eAU = Enum.Parse(typeof(EAssemblyUnit), AU, true); 
    return eAU; 
} 
+3

Das wird es für den * Name * tun, nicht das Attribut description. –

+4

Ich hole dich das nächste Mal, Jon Skeet! * schüttelt winzige Faust an der Wolke * –

0

Sie auch Humanizer f verwenden könnte oder das. Um die Beschreibung zu erhalten können Sie verwenden:

EAssemblyUnit.eUCAL1.Humanize(); 

und die Enum, um wieder aus der Beschreibung können Sie

"UCAL1".DehumanizeTo<EAssemblyUnit>(); 

Haftungsausschluss verwenden: Ich bin der Schöpfer von Humanizer.

Verwandte Themen