Ale*_*x K 453 c# reflection enums .net-attributes
我想知道是否可以获取枚举值的属性而不是枚举本身的属性?例如,假设我有以下枚举:
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
Run Code Online (Sandbox Code Playgroud)
我想要的是枚举类型,产生2元组的枚举字符串值及其描述.
价值很容易:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
Run Code Online (Sandbox Code Playgroud)
但是如何获取描述属性的值,以填充Tuple.Desc?如果属性属于枚举本身,我可以想到如何做到这一点,但我不知道如何从枚举的值中获取它.
Bry*_*owe 463
这应该做你需要的.
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;
Run Code Online (Sandbox Code Playgroud)
Ada*_*ord 262
这段代码应该为你提供一个很好的小扩展方法,可以让你检索一个通用属性.我相信它与上面的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;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 80
这是一个使用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);
}
Run Code Online (Sandbox Code Playgroud)
像这样称呼它:
string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
Run Code Online (Sandbox Code Playgroud)
Tro*_*ord 62
我在这里合并了几个答案,以创建一个更具可扩展性的解决方案.我提供它是为了防止它对将来的其他人有帮助.原帖在这里.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
此解决方案在Enum上创建一对扩展方法.第一个允许您使用反射来检索与您的值相关联的任何属性.第二个特别调用检索DescriptionAttribute并返回它的Description值.
例如,考虑使用DescriptionAttributefrom属性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
}
Run Code Online (Sandbox Code Playgroud)
要使用上述扩展方法,您现在只需调用以下内容:
Console.WriteLine(Days.Mon.ToName());
Run Code Online (Sandbox Code Playgroud)
要么
var day = Days.Mon;
Console.WriteLine(day.ToName());
Run Code Online (Sandbox Code Playgroud)
Fun*_*ame 38
除了AdamCrawford响应之外,我还进一步创建了一个更专业的扩展方法,通过它来获取描述.
public static string GetAttributeDescription(this Enum enumValue)
{
var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
return attribute == null ? String.Empty : attribute.Description;
}
Run Code Online (Sandbox Code Playgroud)
因此,要获得描述,您可以使用原始扩展方法作为
string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description
Run Code Online (Sandbox Code Playgroud)
或者你可以简单地在这里调用扩展方法:
string desc = myEnumVariable.GetAttributeDescription();
Run Code Online (Sandbox Code Playgroud)
哪个应该有希望使您的代码更具可读性.
Ayd*_*din 14
流利的一个班轮......
这里我使用的DisplayAttribute包含Name和Description属性.
public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
return enumType.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
}
Run Code Online (Sandbox Code Playgroud)
例
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);
}
Run Code Online (Sandbox Code Playgroud)
Name: Sea cruise
Description: Cruising on a dinghy
Run Code Online (Sandbox Code Playgroud)
以下是从Display属性获取信息的代码.它使用通用方法来检索属性.如果未找到该属性,则将enum值转换为将pascal/camel case转换为title case的字符串(此处获取的代码)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是转换为标题案例的字符串的扩展方法:
/// <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 "));
}
Run Code Online (Sandbox Code Playgroud)
如果您enum包含这样的值,Equals那么您可能会在此处的许多答案中使用某些扩展来遇到一些错误。这是因为通常假设typeof(YourEnum).GetMember(YourEnum.Value)只会返回一个值,即MemberInfo您的enum. 这是亚当·克劳福德(Adam Crawford)的答案的一个稍微安全的版本。
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
}
Run Code Online (Sandbox Code Playgroud)
GetField在这种情况下效果很好。typeof(YourEnum).GetField(YourEnum.Value)应该产生期望的结果。
public static T GetAttribute<T>(this Enum value) where T : Attribute
{
Type type = value.GetType();
FieldInfo field = type.GetField(value.ToString());
Attribute attr = Attribute.GetCustomAttribute(field, typeof(T), false);
return (T)attr;
}
Run Code Online (Sandbox Code Playgroud)
感谢mjwills指出这一点。
对于一些程序员的幽默来说,有一句笑话:
public static string GetDescription(this Enum value) => value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : string.Empty;
Run Code Online (Sandbox Code Playgroud)
以更易读的形式:
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}')]!");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
274174 次 |
| 最近记录: |