我有一个枚举,每个成员都有一个自定义属性应用于它。如何检索存储在每个属性中的值?
现在我这样做:
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。
当你必须使用反射时,做你想要做的事情有点麻烦:
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);
获得属性的实例后,您可以从中获取在各个枚举值上标记的特定值。
尝试使用通用方法
属性:
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();
}
结果:
星期一
还有另一种方法可以使用泛型:
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;
}
我没试过这个,但看起来这个博客文章描述了你在寻找:Enumeration attribute help
假设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;
}
我想出了一种不同的方法来定位目标枚举值的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)));
}