2010-04-16 2 views
279

Можно создать дубликат:
Getting attributes of Enum’s valueКак получить описание C# Enum из значения?

У меня есть перечисление с описанием атрибутов, как это:

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

Я нашел этот кусок кода для получения описания, основанного на 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(); 
} 

Это позволяет мне писать код, как:

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

То, что я хочу делать, если я знаю, что значение перечисления (например 1) - как я могу получить описание? Другими словами, как преобразовать целое число в значение «Enum», чтобы перейти к моему методу GetDescription?

+0

(! Атрибуты = NULL) всегда будет true и else является избыточным. – Jeff

+1

пространство имен, необходимое для описания, является System.ComponentModel –

ответ

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

по умолчанию базового типа данных для enum в C# является int, вы можете просто бросить его.

+2

совершенным. Именно то, что я хотел. Я знал, что это будет просто! Теперь, если stackoverflow просто позволит мне принять этот ответ ... он говорит, что мне нужно подождать 7 минут. – davekaro

+41

Почему я не нахожу класс Enumerations в .Net framework? –

+53

Класс «Перечисления» - это то, о чем писал сам человек, который задал этот вопрос, и функция GetEnumDescription() находится в вопросе. –

5

Вы не можете сделать это обычным образом: вы можете преобразовать целое число в определенный тип перечисления. Как показал Николас, это тривиальный бросок, если вы только заботитесь об одном виде перечисления, но если вы хотите написать общий метод, который может обрабатывать различные виды перечислений, все становится немного сложнее. Вы хотите, чтобы метод вдоль линий:

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

, но это приводит к ошибке компиляции, что «INT не может быть преобразован в TEnum» (и если вы работаете вокруг этого, что «TEnum не могут быть преобразованы на Enum ").Так что вам нужно, чтобы обмануть компилятор, вставив слепки объекта:

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

Теперь вы можете назвать это, чтобы получить описание для любого типа перечислимого под рукой:

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

Как «GetEnumDescription (1);» лучше, чем GetEnumDescription ((MyEnum) 1); ? – davekaro

+0

@ davekaro: Реализовано вот так, это не так уж и лучше, но более надежная реализация, основанная на дженериках, может сделать это без явного приведения в действие, поэтому вы не рискуете необработанными исключениями, если число фактически не соответствует ни одному из перечисляемые значения. – Aaronaught

+0

Интересно. Просто уточнить для будущих читателей: никто не получит необработанное исключение при явном приведении, если число не соответствует одному из значений перечисления (вы могли бы сказать «MyEnum value = (MyEnum) 5;», и эта строка будет выполняйте просто отлично, но вы должны бомбить в первой строке GetEnumDescription(), как реализовано в исходном вопросе (потому что GetField() вернет значение null, так как не может найти подходящего поля с этим значением). (Чтобы избежать этого, d нужно сначала проверить Enum.IsDefined() и вернуть значение null или пустую строку, либо просто выбросить ArgumentOutOfRangeException самостоятельно.) –

68

Я реализовал это в общий, тип-безопасный способ в Unconstrained Melody - вы будете использовать:

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

Это:

  • Обеспечивает (с ограничениями универсального типа), что значение действительно является значением перечисления
  • Избегает бокс в вашем текущем решении
  • кэширует все описания, чтобы избежать с помощью отражения при каждом вызове
  • Имеет кучу других методы, в том числе возможности разобрать значение из описания

я понимаю, основной ответ был только отлитым из int в MyEnum, но если вы делаете много перечислимых работать то стоит подумать об использовании Безусловных Мелодия :)

+0

Не является ли значение «value» int? Итак, значение Enums.GetDescription ((MyEnum) просто введите int в MyEnum? – davekaro

+0

@ davekaro: он отбрасывает int в MyEnum - но вы не сможете назвать его каким-либо не-перечислением, включая ссылку «Enum». В основном это похоже на ваш код, но с некоторыми generics magic. –

+1

@JonSkeet Я не вижу этот метод в Enum s.cs в https://code.google.com/p/unconstrained-melody/downloads/detail?name=UnconstrainedMelody-0.0.0.2-src.zip&can=2&q= – tom

19

Чтобы сделать это проще в использовании, я написал родовое расширение:

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

теперь я могу написать:

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

Примечание: заменить "Перечни" выше с именем класса

50

Я положил код из принятого ответа в общий метод расширения, поэтому его можно было использовать для всех видов объектов:

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

Используя перечисление, как в оригинальной почте, или любого другого класса, свойство которого украшен атрибутом Описание, код может быть потреблен, как это:

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

Строка классаDesc = myInstance.SomeProperty.DescriptionAttr(); Это не будет работать! Скажем, у вас есть класс Test {public int TestInt {get; задавать;} }. Итак, если вы вызовете новый Test(). TestInt.DescriptionAttr() вы получите нулевое исключение ссылки - 0.GetType(). GetField («0») – Vladimirs

Смежные вопросы