2010-04-16 26 views
279

Powiel możliwe:
Getting attributes of Enum’s valueJak uzyskać C# opis Enum od wartości?

Mam enum wraz z opisem atrybutów tak:

public enum MyEnum 
{ 
    Name1 = 1, 
    [Description("Here is another")] 
    HereIsAnother = 2, 
    [Description("Last one")] 
    LastOne = 3 
} 

Znalazłem ten fragment kodu do pobierania opis oparty na zasadzie Enum

public static string GetEnumDescription(Enum value) 
{ 
    FieldInfo fi = value.GetType().GetField(value.ToString()); 

    DescriptionAttribute[] attributes = 
     (DescriptionAttribute[])fi.GetCustomAttributes(
     typeof(DescriptionAttribute), 
     false); 

    if (attributes != null && 
     attributes.Length > 0) 
     return attributes[0].Description; 
    else 
     return value.ToString(); 
} 

To pozwala mi napisać kod jak:

var myEnumDescriptions = from MyEnum n in Enum.GetValues(typeof(MyEnum)) 
         select new { ID = (int)n, Name = Enumerations.GetEnumDescription(n) }; 

Co chcę zrobić, to jeśli wiem wartość enum (np 1) - jak mogę pobrać opis? Innymi słowy, w jaki sposób mogę przekonwertować liczbę całkowitą na "Wartość wyliczenia", aby przejść do mojej metody GetDescription?

+0

(! Atrybuty = null) będzie zawsze prawda, a ponadto jest zbędny. – Jeff

+1

Przestrzeń nazw wymagana dla Opisu to System.ComponentModel –

Odpowiedz

277
int value = 1; 
string description = Enumerations.GetEnumDescription((MyEnum)value); 

Domyślny typ danych bazowych dla enum w C# jest int, można po prostu rzucić go.

+2

perfect. Dokładnie to, czego chciałem. Wiedziałem, że to będzie proste! Teraz, jeśli stackoverflow po prostu pozwoliłby mi zaakceptować tę odpowiedź ... mówi, że muszę poczekać 7 minut. – davekaro

+41

Dlaczego nie znalazłem żadnej klasy wyliczeń w środowisku .Net? –

+53

Klasa wyliczeń jest czymś, co osoba, która zadała to pytanie, napisała sam siebie, a funkcja GetEnumDescription() jest w pytaniu. –

5

Nie można tego łatwo zrobić w sposób ogólny: można konwertować tylko liczbę całkowitą do określonego typu wyliczenia. Jak pokazał Nicholas, jest to trywialne podejście, jeśli interesuje cię tylko jeden rodzaj enum, ale jeśli chcesz napisać ogólną metodę, która poradzi sobie z różnymi rodzajami wyliczeń, sprawy stają się nieco bardziej skomplikowane. Chcesz metodę wzdłuż linii:

public static string GetEnumDescription<TEnum>(int value) 
{ 
    return GetEnumDescription((Enum)((TEnum)value)); // error! 
} 

ale powoduje to błąd kompilatora, że ​​„int nie mogą być konwertowane do TEnum” (i jeśli to obejść, że „TEnum nie mogą być przekształcone do Enum ").Więc trzeba oszukać kompilator wkładając odlewane do obiektu:

public static string GetEnumDescription<TEnum>(int value) 
{ 
    return GetEnumDescription((Enum)(object)((TEnum)(object)value)); // ugly, but works 
} 

Teraz można nazwać to, aby uzyskać opis jakiegokolwiek rodzaju wyliczenia jest w zasięgu ręki:

GetEnumDescription<MyEnum>(1); 
GetEnumDescription<YourEnum>(2); 
+0

Jak jest "GetEnumDescription (1);" lepsze niż GetEnumDescription ((MyEnum) 1); ? – davekaro

+0

@davekaro: Wdrożony w ten sposób, nie jest wcale o wiele lepszy, ale bardziej niezawodna implementacja oparta na generycznych rozwiązaniach mogłaby to zrobić bez wyraźnej obsady, więc nie ryzykujesz nieobsługiwanymi wyjątkami, jeśli liczba ta nie pasuje do żadnego z wartości wyliczeniowe. – Aaronaught

+0

Interesujące. Aby wyjaśnić przyszłym czytelnikom: Jeden nie otrzyma nieobsługiwanego wyjątku od jawnej obsady, jeśli liczba nie pasuje do jednej z wartości wyliczeniowych (można powiedzieć "Wartość MyEnum = (MyEnum) 5;" i ta linia będzie wykonaj dobrze, ale zbombardujesz pierwszą linię GetEnumDescription(), jak zaimplementowano w pierwotnym pytaniu (ponieważ GetField() zwróci wartość null, ponieważ nie może znaleźć pasującego pola z tą wartością). (Aby ochronić się przed tym, d musi najpierw sprawdzić Enum.IsDefined() i zwrócić wartość null lub pusty łańcuch, lub po prostu samodzielnie rzucić ArgumentOutOfRangeException.) –

68

I wdrożone to w ogólne, typu bezpieczny sposób w Unconstrained Melody - chcesz użyć:

string description = Enums.GetDescription((MyEnum)value); 

to:

  • Zapewnia (z ograniczeniami typów generycznych), że wartość rzeczywiście stanowi wartość enum
  • Unika boks w bieżącym roztworu
  • buforuje wszystkie opisy do uniknięcia przy użyciu odbicia na każde wezwanie
  • ma kilka innych metody, w tym zdolność do analizowania wartości z opisem

ja zrealizować odpowiedź rdzeń był tylko obsada z int do MyEnum, ale jeśli robisz dużo wyliczenia pracy warto myśleć o użyciu Unconstrained Melodia :)

+0

Czy "wartość" nie jest wartością int, więc nie jest wartością Enums.GetDescription ((MyEnum)) po prostu wyrzuć int do MyEnum? – davekaro

+0

@davekaro: Rzuca int do MyEnum - ale nie będziesz w stanie nazwać go żadnym non-enum, w tym odniesieniem "Enum". Zasadniczo to jest jak twój kod, ale z niektórymi generics magic. –

+1

@JonSkeet Nie widzę tej metody w Enum s.cs w https://code.google.com/p/unconstrained-melody/downloads/detail?name=UnconstrainedMelody-0.0.0.2-src.zip&can=2&q= – tom

19

Aby to łatwiejsze w użyciu, napisałem rozszerzenie Generic:

public static string ToDescription<TEnum>(this TEnum EnumValue) where TEnum : struct 
{ 
    return Enumerations.GetEnumDescription((Enum)(object)((TEnum)EnumValue)); 
} 

teraz mogę napisać:

 MyEnum my = MyEnum.HereIsAnother; 
     string description = my.ToDescription(); 
     System.Diagnostics.Debug.Print(description); 

Uwaga: Wymienić "wyliczenia" powyżej z nazwą klasy

50

Umieściłem kod razem z zaakceptowanej odpowiedzi w ogólnej metodzie rozszerzenia, aby mógł on być używany do wszystkich rodzajów obiektów:

public static string DescriptionAttr<T>(this T source) 
{ 
    FieldInfo fi = source.GetType().GetField(source.ToString()); 

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
     typeof(DescriptionAttribute), false); 

    if (attributes != null && attributes.Length > 0) return attributes[0].Description; 
    else return source.ToString(); 
} 

Korzystanie enum jak w oryginalnym poście, lub jakiejkolwiek innej klasy, której nieruchomość jest ozdobiona atrybutu Opis, kod może być spożywany tak:

string enumDesc = MyEnum.HereIsAnother.DescriptionAttr(); 
string classDesc = myInstance.SomeProperty.DescriptionAttr(); 
+2

string classDesc = myInstance.SomeProperty.DescriptionAttr(); To nie zadziała! Powiedzmy, że masz klasę Test {public int TestInt {get; set;}}. Więc jeśli nazwiesz nowy Test(). TestInt.DescriptionAttr() otrzymasz wyjątek odwołania zerowego - 0.GetType(). GetField ("0") – Vladimirs