J'ai une énumération où chaque membre a un attribut personnalisé qui lui est appliqué. Comment puis-je récupérer la valeur stockée dans chaque attribut?
En ce moment, je fais ceci:
var attributes = typeof ( EffectType ).GetCustomAttributes ( false );
foreach ( object attribute in attributes )
{
GPUShaderAttribute attr = ( GPUShaderAttribute ) attribute;
if ( attr != null )
return attr.GPUShader;
}
return 0;
Un autre problème est, s'il n'est pas trouvé, que dois-je retourner? 0 est implcity convertible en toute énumération, non? Voilà pourquoi je l'ai retourné.
Oublié de mentionner, le code ci-dessus renvoie 0 pour chaque membre enum.
C'est un peu compliqué de faire ce que vous essayez de faire car vous devez utiliser la réflexion:
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;
}
Cela retournera une instance de GPUShaderAttribute
qui est pertinente pour celle marquée sur la valeur enum de EffectType
. Vous devez l'appeler sur une valeur spécifique de l'énumération EffectType
:
GPUShaderAttribute attribute = GetGPUShader(EffectType.MyEffect);
Une fois que vous avez l'instance de l'attribut, vous pouvez en extraire les valeurs spécifiques qui sont marquées sur les valeurs d'énumération individuelles.
Essayez d'utiliser une méthode générique
Attribut:
class DayAttribute : Attribute
{
public string Name { get; private set; }
public DayAttribute(string name)
{
this.Name = name;
}
}
Enum:
enum Days
{
[Day("Saturday")]
Sat,
[Day("Sunday")]
Sun,
[Day("Monday")]
Mon,
[Day("Tuesday")]
Tue,
[Day("Wednesday")]
Wed,
[Day("Thursday")]
Thu,
[Day("Friday")]
Fri
}
Méthode générique:
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(); }
Invoquer:
static void Main(string[] args)
{
var day = Days.Mon;
Console.WriteLine(day.GetAttribute<DayAttribute>().Name);
Console.ReadLine();
}
Résultat:
Lundi
Il existe une autre méthode pour ce faire avec les génériques:
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;
}
En supposant que GPUShaderAttribute
:
[AttributeUsage(AttributeTargets.Field,AllowMultiple =false)]
public class GPUShaderAttribute: Attribute
{
public GPUShaderAttribute(string value)
{
Value = value;
}
public string Value { get; internal set; }
}
Ensuite, nous pourrions écrire quelques méthodes génériques pour renvoyer un dictionnaire des valeurs d'énumération et de l'objet 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;
}
Retournez ensuite l'ensemble avec cette méthode.
/// <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;
}
Si vous vouliez juste une valeur de chaîne, je recommanderais un itinéraire légèrement différent.
/// <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;
}
Je n'ai pas essayé cela, mais il semble que ce billet de blog décrit ce que vous recherchez: Aide sur les attributs d'énumération
J'ai trouvé une méthode différente pour localiser l'élément FieldInfo pour la valeur énumérée ciblée. La localisation de la valeur énumérée en la convertissant en une chaîne semblait incorrecte, j'ai donc opté pour vérifier la liste des champs avec LINQ:
Type enumType = value.GetType();
FieldInfo[] fields = enumType.GetFields();
FieldInfo fi = fields.Where(tField =>
tField.IsLiteral &&
tField.GetValue(null).Equals(value)
).First();
Donc, tous glommed ensemble, j'ai:
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)));
}