如何获取枚举的自定义属性值?
Posted
技术标签:
【中文标题】如何获取枚举的自定义属性值?【英文标题】:How to get Custom Attribute values for enums? 【发布时间】:2011-07-03 03:16:54 【问题描述】:我有一个枚举,其中每个成员都应用了一个自定义属性。如何检索存储在每个属性中的值?
现在我这样做:
var attributes = typeof ( EffectType ).GetCustomAttributes ( false );
foreach ( object attribute in attributes )
GPUShaderAttribute attr = ( GPUShaderAttribute ) attribute;
if ( attr != null )
return attr.GPUShader;
return 0;
另一个问题是,如果没有找到,我应该返回什么? 0 可以转换为任何枚举,对吧?这就是我退货的原因。
忘了说,上面的代码为每个枚举成员返回 0。
【问题讨论】:
What AttributeTarget should I use for enum members? 的可能重复项 不,这不一样。在这里,我只是尝试使用反射获取枚举成员上设置的自定义属性。 Getting attributes of Enum's value的可能重复 【参考方案1】:尝试使用通用方法
属性:
class DayAttribute : Attribute
public string Name get; private set;
public DayAttribute(string name)
this.Name = name;
枚举:
enum Days
[Day("Saturday")]
Sat,
[Day("Sunday")]
Sun,
[Day("Monday")]
Mon,
[Day("Tuesday")]
Tue,
[Day("Wednesday")]
Wed,
[Day("Thursday")]
Thu,
[Day("Friday")]
Fri
通用方法:
public static TAttribute GetAttribute<TAttribute>(this Enum value) where TAttribute : Attribute var enumType = value.GetType(); var name = Enum.GetName(enumType, value); return enumType.GetField(name).GetCustomAttributes(false).OfType<TAttribute>().SingleOrDefault();
调用:
static void Main(string[] args)
var day = Days.Mon;
Console.WriteLine(day.GetAttribute<DayAttribute>().Name);
Console.ReadLine();
结果:
星期一
【讨论】:
希望我能给这个答案投票 100 次!!好东西:-) 是的,可以工作.. 但如果您没有为特定的枚举值声明属性,您可能会在 null 上调用 .Name。即您应该在调用 .Name 之前检查 day.GetAttribute做你想做的事情有点乱,因为你必须使用反射:
public GPUShaderAttribute GetGPUShader(EffectType effectType)
MemberInfo memberInfo = typeof(EffectType).GetMember(effectType.ToString())
.FirstOrDefault();
if (memberInfo != null)
GPUShaderAttribute attribute = (GPUShaderAttribute)
memberInfo.GetCustomAttributes(typeof(GPUShaderAttribute), false)
.FirstOrDefault();
return attribute;
return null;
这将返回GPUShaderAttribute
的一个实例,该实例与EffectType
的枚举值上标记的实例相关。您必须在 EffectType
枚举的特定值上调用它:
GPUShaderAttribute attribute = GetGPUShader(EffectType.MyEffect);
一旦您拥有属性的实例,您就可以从中获取特定的值,这些值标记在各个枚举值上。
【讨论】:
谢谢,它的工作原理。我不知道会这么复杂。但这是最简单的方法,对吧?你也知道为什么我的版本不起作用。我认为由于无法实例化枚举,因此使用 enum.getCustomAttributes 会起作用。 @Joan:据我所知,这是最简单的方法。您的方法不起作用,因为您获取的是在枚举类型而不是类型的值上定义的属性。 谢谢阿德里安,现在说得通了。【参考方案3】:还有另一种使用泛型的方法:
public static T GetAttribute<T>(Enum enumValue) where T: Attribute
T attribute;
MemberInfo memberInfo = enumValue.GetType().GetMember(enumValue.ToString())
.FirstOrDefault();
if (memberInfo != null)
attribute = (T) memberInfo.GetCustomAttributes(typeof (T), false).FirstOrDefault();
return attribute;
return null;
【讨论】:
我喜欢这个,但它没有考虑到同一属性有多个实例的可能性。我拿走了你所拥有的并将其修改为使用 T[] 而不是 T,然后删除了 GetCustomAttributes 上的 FirstOrDefault()。【参考方案4】:假设GPUShaderAttribute
:
[AttributeUsage(AttributeTargets.Field,AllowMultiple =false)]
public class GPUShaderAttribute: Attribute
public GPUShaderAttribute(string value)
Value = value;
public string Value get; internal set;
然后我们可以编写一些通用方法来返回枚举值和GPUShaderAttribute
对象的字典。
/// <summary>
/// returns the attribute for a given enum
/// </summary>
public static TAttribute GetAttribute<TAttribute>(IConvertible @enum)
TAttribute attributeValue = default(TAttribute);
if (@enum != null)
FieldInfo fi = @enum.GetType().GetField(@enum.ToString());
attributeValue = fi == null ? attributeValue : (TAttribute)fi.GetCustomAttributes(typeof(TAttribute), false).DefaultIfEmpty(null).FirstOrDefault();
return attributeValue;
然后用这个方法返回整个集合。
/// <summary>
/// Returns a dictionary of all the Enum fields with the attribute.
/// </summary>
public static Dictionary<Enum, RAttribute> GetEnumObjReference<TEnum, RAttribute>()
Dictionary<Enum, RAttribute> _dict = new Dictionary<Enum, RAttribute>();
Type enumType = typeof(TEnum);
Type enumUnderlyingType = Enum.GetUnderlyingType(enumType);
Array enumValues = Enum.GetValues(enumType);
foreach (Enum enumValue in enumValues)
_dict.Add(enumValue, GetAttribute<RAttribute>(enumValue));
return _dict;
如果你只是想要一个字符串值,我会推荐一个稍微不同的路线。
/// <summary>
/// Returns the string value of the custom attribute property requested.
/// </summary>
public static string GetAttributeValue<TAttribute>(IConvertible @enum, string propertyName = "Value")
TAttribute attribute = GetAttribute<TAttribute>(@enum);
return attribute == null ? null : attribute.GetType().GetProperty(propertyName).GetValue(attribute).ToString();
/// <summary>
/// Returns a dictionary of all the Enum fields with the string of the property from the custom attribute nulls default to the enumName
/// </summary>
public static Dictionary<Enum, string> GetEnumStringReference<TEnum, RAttribute>(string propertyName = "Value")
Dictionary<Enum, string> _dict = new Dictionary<Enum, string>();
Type enumType = typeof(TEnum);
Type enumUnderlyingType = Enum.GetUnderlyingType(enumType);
Array enumValues = Enum.GetValues(enumType);
foreach (Enum enumValue in enumValues)
string enumName = Enum.GetName(typeof(TEnum), enumValue);
string decoratorValue = Common.GetAttributeValue<RAttribute>(enumValue, propertyName) ?? enumName;
_dict.Add(enumValue, decoratorValue);
return _dict;
【讨论】:
【参考方案5】:我想出了一种不同的方法来定位目标枚举值的 FieldInfo 元素。通过将枚举值转换为字符串来定位枚举值感觉不对,所以我选择使用 LINQ 检查字段列表:
Type enumType = value.GetType();
FieldInfo[] fields = enumType.GetFields();
FieldInfo fi = fields.Where(tField =>
tField.IsLiteral &&
tField.GetValue(null).Equals(value)
).First();
所以我所有的都发光了:
public static TAttribute GetAttribute<TAttribute>(this Enum value)
where TAttribute : Attribute
Type enumType = value.GetType();
FieldInfo[] fields = enumType.GetFields();
FieldInfo fi = fields.Where(tField =>
tField.IsLiteral &&
tField.GetValue(null).Equals(value)
).First();
// If we didn't get, return null
if (fi == null) return null;
// We found the element (which we always should in an enum)
// return the attribute if it exists.
return (TAttribute)(fi.GetCustomAttribute(typeof(TAttribute)));
【讨论】:
这是一个非常干净的通用解决方案。效果很好!【参考方案6】:public string GetEnumAttributeValue(Enum enumValue, Type attributeType, string attributePropertyName)
/* New generic version (GetEnumDescriptionAttribute results can be achieved using this new GetEnumAttribute with a call like (enumValue, typeof(DescriptionAttribute), "Description")
* Extracts a given attribute value from an enum:
*
* Ex:
* public enum X
*
[MyAttribute(myProp = "aaaa")]
* x1,
* x2,
* [Description("desc")]
* x3
*
*
* Usage:
* GetEnumAttribute(X.x1, typeof(MyAttribute), "myProp") returns "aaaa"
* GetEnumAttribute(X.x2, typeof(MyAttribute), "myProp") returns string.Empty
* GetEnumAttribute(X.x3, typeof(DescriptionAttribute), "Description") returns "desc"
*/
var attributeObj = enumValue.GetType()?.GetMember(enumValue.ToString())?.FirstOrDefault()?.GetCustomAttributes(attributeType, false)?.FirstOrDefault();
if (attributeObj == null)
return string.Empty;
else
try
var attributeCastedObj = Convert.ChangeType(attributeObj, attributeType);
var attributePropertyValue = attributeType.GetProperty(attributePropertyName)?.GetValue(attributeCastedObj);
return attributePropertyValue?.ToString() ?? string.Empty;
catch (Exception ex)
return string.Empty;
【讨论】:
以上是关于如何获取枚举的自定义属性值?的主要内容,如果未能解决你的问题,请参考以下文章
如何从自定义用户控件 WPF、C# 中的枚举自定义属性中获取值?
如何在 ASP.Net MVC 5 视图中获取 ApplicationUser 的自定义属性值?