我想知道是否可以获取枚举值的属性而不是枚举本身的属性?例如,假设我有以下枚举:
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
我想要的是enum类型,产生2元组的枚举字符串值及其描述。
价值很容易:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
但是如何获取描述属性的值,以填充Tuple.Desc?如果属性属于枚举本身,我可以想到如何做到这一点,但我不知道如何从枚举的值中获取它。
答案 0 :(得分:457)
这应该做你需要的。
var type = typeof(FunkyAttributesEnum);
var memInfo = type.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var mem = memInfo.FirstOrDefault(m => m.DeclaringType == type);
var attributes = mem.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
答案 1 :(得分:247)
这段代码应该为你提供一个很好的小扩展方法,可以让你检索一个通用属性。我相信它与上面的lambda函数不同,因为它更简单易用 - 你需要传递泛型类型。
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;
}
}
答案 2 :(得分:79)
这是一个使用lambda进行选择的通用实现
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);
答案 3 :(得分:56)
我在这里合并了几个答案,以创建一个更具可扩展性的解决方案。我提供它是为了防止它对将来的其他人有帮助。原始发布here。
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());
答案 4 :(得分:38)
除了AdamCrawford response之外,我还进一步创建了一种更专业的扩展方法,通过它来提供描述。
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();
哪个应该有希望使您的代码更具可读性。
答案 5 :(得分:14)
流畅的一个班轮......
我在这里使用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
答案 6 :(得分:7)
以下是从Display属性获取信息的代码。它使用通用方法来检索属性。如果未找到该属性,则会将enum值转换为将pascal / camel case转换为title case的字符串(获取的代码here)
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)
{
//https://stackoverflow.com/a/155486/150342
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 "));
}
答案 7 :(得分:4)
从枚举中获取字典。
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方法
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
}
答案 8 :(得分:3)
我实现了这个扩展方法,以便从枚举值中获取描述。它适用于所有类型的枚举。
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();
}
}
答案 9 :(得分:3)
这是使用System.Reflection.TypeExtensions的AdamCrawford答案的.NET核心版本;
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];
}
}
答案 10 :(得分:3)
添加我的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();
答案 11 :(得分:2)
我这个答案是从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;
}
}
}
答案 12 :(得分:2)
利用一些较新的C#语言功能,您可以减少行数:
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();
答案 13 :(得分:1)
对于某些程序员的幽默,开个玩笑作为笑话:
public static string GetDescription(this Enum value) => value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : string.Empty;
以更具可读性的形式:
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
public static class EnumExtensions
{
// get description from enum:
public static string GetDescription(this Enum value)
{
return value.GetType().
GetMember(value.ToString()).
First().
GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute
? attribute.Description
: throw new Exception($"Enum member '{value.GetType()}.{value}' doesn't have a [DescriptionAttribute]!");
}
// get enum from description:
public static T GetEnum<T>(this string description) where T : Enum
{
foreach (FieldInfo fieldInfo in typeof(T).GetFields())
{
if (fieldInfo.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute && attribute.Description == description)
return (T)fieldInfo.GetRawConstantValue();
}
throw new Exception($"Enum '{typeof(T)}' doesn't have a member with a [DescriptionAttribute('{description}')]!");
}
}
答案 14 :(得分:1)
此扩展方法将使用其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 :(得分:1)
如果您想要完整的名单,您可以执行类似
的操作typeof (PharmacyConfigurationKeys).GetFields()
.Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
.Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
答案 16 :(得分:0)
或者,您可以执行以下操作:
List<SelectListItem> selectListItems = new List<SelectListItem>();
foreach (var item in typeof(PaymentTerm).GetEnumValues())
{
var type = item.GetType();
var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
selectListItems.Add(new SelectListItem(name, type.Name));
}
答案 17 :(得分:0)
Bryan Rowe 和 AdamCrawford ,谢谢您的回答!
但是,如果有人需要获取Discription(不是扩展名)的方法,则可以使用它:
string GetEnumDiscription(Enum EnumValue)
{
var type = EnumValue.GetType();
var memInfo = type.GetMember(EnumValue.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? ((DescriptionAttribute)attributes[0]).Description : null;
}
答案 18 :(得分:0)
这是我无需在.NET core 3.1中使用自定义帮助程序或扩展程序即可解决的方法。
public enum YourEnum
{
[Display(Name = "Suryoye means Arameans")]
SURYOYE = 0,
[Display(Name = "Oromoye means Syriacs")]
OROMOYE = 1,
}
@using Enumerations
foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
{
<h1>@name.Text</h1>
}
答案 19 :(得分:0)
如果您想要更好的性能,这是可行的方法:
public static class AdvancedEnumExtensions
{
/// <summary>
/// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
/// </summary>
public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
{
return GetField(value)?.GetCustomAttribute<T>(inherit: false);
}
/// <summary>
/// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
/// </summary>
public static FieldInfo GetField(this Enum value)
{
ulong u64 = ToUInt64(value);
return value
.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
.FirstOrDefault();
}
/// <summary>
/// Checks if an enum constant is defined for this enum value
/// </summary>
public static bool IsDefined(this Enum value)
{
return GetField(value) != null;
}
/// <summary>
/// Converts the enum value to UInt64
/// </summary>
public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);
private static ulong ToUInt64(object value)
{
switch (Convert.GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Char:
case TypeCode.Boolean:
return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
default: throw new InvalidOperationException("UnknownEnumType");
}
}
}
为什么这会有更好的性能?
因为所有内置方法都使用与此非常相似的代码,除了它们还运行了许多我们不在乎的其他代码。一般来说,C#的Enum代码非常糟糕。
上面的代码已经过Linq验证和简化,因此只包含我们关心的位。
首先涉及Enum.ToString()-vs- Enum.GetName(..)
始终使用后者。 (或者更好,但都不是,这将在下面变得清楚。)
ToString()在内部使用后者,但同样,它还会执行其他一些我们不想要的东西,例如尝试组合标志,打印数字等。我们只对枚举内部定义的常量感兴趣。
Enum.GetName依次获取所有字段,为所有名称创建一个字符串数组,在其所有RawConstantValues上使用上述ToUInt64创建所有值的UInt64数组,并根据UInt64值对两个数组进行排序,最后得到通过在UInt64数组中执行BinarySearch来查找所需值的索引,从名称数组中获取名称。
...然后我们将这些字段扔掉,然后使用该名称将排序后的数组移开以再次找到该字段。
一个字:“ U!”
答案 20 :(得分:0)
如果您的enum
包含一个类似Equals
的值,则可能会在此处的许多答案中使用一些扩展名遇到一些错误。这是因为通常假设typeof(YourEnum).GetMember(YourEnum.Value)
仅返回一个值,即您的MemberInfo
的{{1}}。这是一个稍微更安全的版本Adam Crawford's answer。
enum
答案 21 :(得分:0)
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&#34;等于&#34;
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() 如果displayname和enum name相同,则获取null .....
答案 22 :(得分:0)
如果有帮助我会与您分享我的解决方案: 自定义属性的定义:
[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");
}
}
希望有所帮助
答案 23 :(得分:-1)
或者,您可以执行以下操作:
Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
{
{ FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
{ FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
};
并获得以下描述:
string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
在我看来,这是一种更有效的方式来做你想要完成的事情,因为不需要反思..
答案 24 :(得分:-3)
您还可以定义类似Name_Without_Spaces
的枚举值,并在需要说明时使用Name_Without_Spaces.ToString().Replace('_', ' ')
将下划线替换为空格。