Получение атрибутов значения Enum
Я хотел бы знать, можно ли получить атрибуты значений перечисления, а не самого перечисления? Например, предположим, что у меня есть следующее перечисление:
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
Мне нужно задать тип перечисления, произвести 2-строчные значения строки перечисления и его описание.
Значение было легко:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
Но как мне получить значение атрибута описания, чтобы заполнить Tuple.Desc? Я могу подумать, как это сделать, если атрибут принадлежит самому перечислению, но я не понимаю, как получить его из значения перечисления.
Ответы
Ответ 1
Это должно делать то, что вам нужно.
var enumType = typeof(FunkyAttributesEnum);
var memberInfos = enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == enumType);
var valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)valueAttributes[0]).Description;
Ответ 2
Этот фрагмент кода должен дать вам небольшой метод расширения для любого перечисления, который позволяет получить общий атрибут. Я считаю, что это отличается от функции лямбда выше, потому что она проще в использовании и немного - вам нужно только передать общий тип.
public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (attributes.Length > 0) ? (T)attributes[0] : null;
}
}
Ответ 3
Это общая реализация с использованием лямбда для выбора
public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
where T : Attribute
{
T attribute =
enumeration
.GetType()
.GetMember(enumeration.ToString())
.Where(member => member.MemberType == MemberTypes.Field)
.FirstOrDefault()
.GetCustomAttributes(typeof(T), false)
.Cast<T>()
.SingleOrDefault();
if (attribute == null)
return default(Expected);
return expression(attribute);
}
Назовите это так:
string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
Ответ 4
Я объединил пару ответов здесь, чтобы создать немного более расширяемое решение. Я предоставляю это на всякий случай, если это пригодится кому-то еще в будущем. Оригинальное размещение здесь.
using System;
using System.ComponentModel;
public static class EnumExtensions {
// This extension method is broken out so you can use a similar pattern with
// other MetaData elements in the future. This is your base method for each.
public static T GetAttribute<T>(this Enum value) where T : Attribute {
var type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
return attributes.Length > 0
? (T)attributes[0]
: null;
}
// This method creates a specific call to the above method, requesting the
// Description MetaData attribute.
public static string ToName(this Enum value) {
var attribute = value.GetAttribute<DescriptionAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
}
Это решение создает пару методов расширения в Enum. Первый позволяет использовать отражение, чтобы получить любой атрибут, связанный с вашим значением. Второй вызов вызывает извлечение DescriptionAttribute
и возвращает ему значение Description
.
В качестве примера рассмотрим использование атрибута DescriptionAttribute
из System.ComponentModel
using System.ComponentModel;
public enum Days {
[Description("Sunday")]
Sun,
[Description("Monday")]
Mon,
[Description("Tuesday")]
Tue,
[Description("Wednesday")]
Wed,
[Description("Thursday")]
Thu,
[Description("Friday")]
Fri,
[Description("Saturday")]
Sat
}
Чтобы использовать вышеупомянутый метод расширения, вы бы просто вызвали следующее:
Console.WriteLine(Days.Mon.ToName());
или же
var day = Days.Mon;
Console.WriteLine(day.ToName());
Ответ 5
В дополнение к ответу от AdamCrawford, я также создал более специализированные методы расширения, которые поддерживают его, чтобы получить описание.
public static string GetAttributeDescription(this Enum enumValue)
{
var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
return attribute == null ? String.Empty : attribute.Description;
}
следовательно, чтобы получить описание, вы можете использовать оригинальный метод расширения как
string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description
или вы можете просто вызвать метод расширения здесь как:
string desc = myEnumVariable.GetAttributeDescription();
Что, надеюсь, сделает ваш код более читабельным.
Ответ 6
Свободный один вкладыш...
Здесь я использую DisplayAttribute
, который содержит свойства Name
и Description
.
public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
return enumType.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
}
Пример
public enum ModesOfTransport
{
[Display(Name = "Driving", Description = "Driving a car")] Land,
[Display(Name = "Flying", Description = "Flying on a plane")] Air,
[Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
}
void Main()
{
ModesOfTransport TransportMode = ModesOfTransport.Sea;
DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
}
Выход
Name: Sea cruise
Description: Cruising on a dinghy
Ответ 7
Вот код для получения информации из атрибута Display. Он использует общий метод для извлечения атрибута. Если атрибут не найден, он преобразует значение перечисления в строку с флагом pascal/camel, преобразованным в заголовок (полученный код здесь)
public static class EnumHelper
{
// Get the Name value of the Display attribute if the
// enum has one, otherwise use the value converted to title case.
public static string GetDisplayName<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
{
var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
}
// Get the ShortName value of the Display attribute if the
// enum has one, otherwise use the value converted to title case.
public static string GetDisplayShortName<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
{
var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
}
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="TEnum">The enum type</typeparam>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="value">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
private static T GetAttributeOfType<TEnum, T>(this TEnum value)
where TEnum : struct, IConvertible
where T : Attribute
{
return value.GetType()
.GetMember(value.ToString())
.First()
.GetCustomAttributes(false)
.OfType<T>()
.LastOrDefault();
}
}
И это метод расширения для строк для преобразования в заголовок:
/// <summary>
/// Converts camel case or pascal case to separate words with title case
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ToSpacedTitleCase(this string s)
{
///questions/19498/net-how-can-you-split-a-caps-delimited-string-into-an-array/145002#145002
CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;
return textInfo
.ToTitleCase(Regex.Replace(s,
"([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
}
Ответ 8
Получить словарь из перечисления.
public static IDictionary<string, int> ToDictionary(this Type enumType)
{
return Enum.GetValues(enumType)
.Cast<object>()
.ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k);
}
Теперь назовите это как...
var dic = typeof(ActivityType).ToDictionary();
EnumDecription Ext Method
public static string ToEnumDescription(this Enum en) //ext method
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
return ((DescriptionAttribute)attrs[0]).Description;
}
return en.ToString();
}
public enum ActivityType
{
[Description("Drip Plan Email")]
DripPlanEmail = 1,
[Description("Modification")]
Modification = 2,
[Description("View")]
View = 3,
[Description("E-Alert Sent")]
EAlertSent = 4,
[Description("E-Alert View")]
EAlertView = 5
}
Ответ 9
Я реализовал этот метод расширения, чтобы получить описание из значений перечисления. Он работает для всех видов перечислений.
public static class EnumExtension
{
public static string ToDescription(this System.Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
}
Ответ 10
Здесь версия .NET Core для AdamCrawford, используя System.Reflection.TypeExtensions;
public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (T)attributes?.ToArray()[0];
}
}
Ответ 11
Добавление моего решения для Net Framework и NetCore.
Я использовал это для моей реализации Net Framework:
public static class EnumerationExtension
{
public static string Description( this Enum value )
{
// get attributes
var field = value.GetType().GetField( value.ToString() );
var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );
// return description
return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
}
}
Это не работает для NetCore, поэтому я изменил его, чтобы сделать это:
public static class EnumerationExtension
{
public static string Description( this Enum value )
{
// get attributes
var field = value.GetType().GetField( value.ToString() );
var attributes = field.GetCustomAttributes( false );
// Description is in a hidden Attribute class called DisplayAttribute
// Not to be confused with DisplayNameAttribute
dynamic displayAttribute = null;
if (attributes.Any())
{
displayAttribute = attributes.ElementAt( 0 );
}
// return description
return displayAttribute?.Description ?? "Description Not Found";
}
}
Пример перечисления:
public enum ExportTypes
{
[Display( Name = "csv", Description = "text/csv" )]
CSV = 0
}
Использование образца для статического добавленного:
var myDescription = myEnum.Description();
Ответ 12
Я отвечу, чтобы установить поле со списком из атрибутов enum, что было здорово.
Затем мне нужно было закодировать обратное, чтобы я мог получить выделение из поля и вернуть перечисление в правильный тип.
Я также модифицировал код для обработки случая, когда отсутствовал атрибут
Для преимуществ следующего человека, вот мое окончательное решение
public static class Program
{
static void Main(string[] args)
{
// display the description attribute from the enum
foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour)))
{
Console.WriteLine(EnumExtensions.ToName(type));
}
// Get the array from the description
string xStr = "Yellow";
Colour thisColour = EnumExtensions.FromName<Colour>(xStr);
Console.ReadLine();
}
public enum Colour
{
[Description("Colour Red")]
Red = 0,
[Description("Colour Green")]
Green = 1,
[Description("Colour Blue")]
Blue = 2,
Yellow = 3
}
}
public static class EnumExtensions
{
// This extension method is broken out so you can use a similar pattern with
// other MetaData elements in the future. This is your base method for each.
public static T GetAttribute<T>(this Enum value) where T : Attribute
{
var type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
// check if no attributes have been specified.
if (((Array)attributes).Length > 0)
{
return (T)attributes[0];
}
else
{
return null;
}
}
// This method creates a specific call to the above method, requesting the
// Description MetaData attribute.
public static string ToName(this Enum value)
{
var attribute = value.GetAttribute<DescriptionAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
/// <summary>
/// Find the enum from the description attribute.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="desc"></param>
/// <returns></returns>
public static T FromName<T>(this string desc) where T : struct
{
string attr;
Boolean found = false;
T result = (T)Enum.GetValues(typeof(T)).GetValue(0);
foreach (object enumVal in Enum.GetValues(typeof(T)))
{
attr = ((Enum)enumVal).ToName();
if (attr == desc)
{
result = (T)enumVal;
found = true;
break;
}
}
if (!found)
{
throw new Exception();
}
return result;
}
}
}
Ответ 13
Воспользовавшись некоторыми новыми функциями языка С#, вы можете уменьшить количество строк:
public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumVal) where TAttribute : Attribute
{
var memberInfo = enumVal.GetType().GetMember(enumVal.ToString());
return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType<TAttribute>().FirstOrDefault();
}
public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute<DescriptionAttribute>()?.Description ?? enumValue.ToString();
Ответ 14
Этот метод расширения получит строковое представление значения перечисления, используя его XmlEnumAttribute. Если XmlEnumAttribute не присутствует, он возвращается к enum.ToString().
public static string ToStringUsingXmlEnumAttribute<T>(this T enumValue)
where T: struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
string name;
var type = typeof(T);
var memInfo = type.GetMember(enumValue.ToString());
if (memInfo.Length == 1)
{
var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);
if (attributes.Length == 1)
{
name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name;
}
else
{
name = enumValue.ToString();
}
}
else
{
name = enumValue.ToString();
}
return name;
}
Ответ 15
И если вам нужен полный список имен, вы можете сделать что-то вроде
typeof (PharmacyConfigurationKeys).GetFields()
.Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
.Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
Ответ 16
Если ваше enum
содержит значение типа Equals
вы можете столкнуться с несколькими ошибками, используя некоторые расширения во многих ответах. Это потому, что обычно предполагается, что typeof(YourEnum).GetMember(YourEnum.Value)
будет возвращать только одно значение, которое является MemberInfo
вашего enum
. Здесь чуть более безопасный вариант ответа Адама Кроуфорда.
public static class AttributeExtensions
{
#region Methods
public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
{
var type = enumValue.GetType();
var memberInfo = type.GetMember(enumValue.ToString());
var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
return attribute is T ? (T)attribute : null;
}
#endregion
}
Ответ 17
Ребята, если это поможет, я поделюсь с вами своим решением:
Определение пользовательского атрибута:
[AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
public class EnumDisplayName : Attribute
{
public string Name { get; private set; }
public EnumDisplayName(string name)
{
Name = name;
}
}
Теперь, потому что мне это нужно в определении HtmlHelper расширения HtmlHelper:
public static class EnumHelper
{
public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
{
//Get every fields from enum
var fields = priceType.GetType().GetFields();
//Foreach field skipping 1`st fieldw which keeps currently sellected value
for (int i = 0; i < fields.Length;i++ )
{
//find field with same int value
if ((int)fields[i].GetValue(priceType) == (int)priceType)
{
//get attributes of found field
var attributes = fields[i].GetCustomAttributes(false);
if (attributes.Length > 0)
{
//return name of found attribute
var retAttr = (EnumDisplayName)attributes[0];
return retAttr.Name;
}
}
}
//throw Error if not found
throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
}
}
Надеюсь, что это поможет
Ответ 18
public enum DataFilters
{
[Display(Name= "Equals")]
Equals = 1,// Display Name and Enum Name are same
[Display(Name= "Does Not Equal")]
DoesNotEqual = 2, // Display Name and Enum Name are different
}
Теперь это приведет к ошибке в этом случае 1 "Равно"
public static string GetDisplayName(this Enum enumValue)
{
var enumMember = enumValue.GetType().GetMember(enumValue.ToString()).First();
return enumMember.GetCustomAttribute<DisplayAttribute>() != null ? enumMember.GetCustomAttribute<DisplayAttribute>().Name : enumMember.Name;
}
поэтому, если это одно и то же имя переименования возврата, а не отображаемое имя, потому что enumMember.GetCustomAttribute() получает значение null, если displayname и имя перечисления одинаковы.....
Ответ 19
В качестве альтернативы вы можете сделать следующее:
Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
{
{ FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
{ FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
};
И получите описание со следующим:
string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
По-моему, это более эффективный способ делать то, что вы хотите достичь, поскольку не требуется никакого размышления.
Ответ 20
Вы также можете определить значение перечислимого типа, например Name_Without_Spaces
, и если вы хотите, чтобы в описании использовалось Name_Without_Spaces.ToString().Replace('_', ' ')
, чтобы заменить символы подчеркивания пробелами.