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