Reflexión: obtenga el nombre y el valor del atributo en la propiedad

Tengo una clase, vamos a llamarlo Libro con una propiedad llamada Nombre. Con esa propiedad, tengo un atributo asociado a ella.

public class Book { [Author("AuthorName")] public string Name { get; private set; } } 

En mi método principal, estoy usando el reflection y deseo obtener un par de valores clave de cada atributo para cada propiedad. Por lo tanto, en este ejemplo, esperaría ver “Autor” para el nombre del atributo y “Nombre del autor” para el valor del atributo.

Pregunta: ¿Cómo obtengo el nombre y el valor del atributo en mis propiedades usando Reflection?

Utilice typeof(Book).GetProperties() para obtener una matriz de instancias de PropertyInfo . Luego use GetCustomAttribute() en cada PropertyInfo para ver si alguno de ellos tiene el tipo de atributo de Author . Si lo hacen, puede obtener el nombre de la propiedad de la información de la propiedad y los valores de atributo del atributo.

Algo similar a esto para escanear un tipo de propiedades que tienen un tipo de atributo específico y para devolver datos en un diccionario (tenga en cuenta que esto se puede hacer más dynamic pasando tipos a la rutina):

 public static Dictionary GetAuthors() { Dictionary _dict = new Dictionary(); PropertyInfo[] props = typeof(Book).GetProperties(); foreach (PropertyInfo prop in props) { object[] attrs = prop.GetCustomAttributes(true); foreach (object attr in attrs) { AuthorAttribute authAttr = attr as AuthorAttribute; if (authAttr != null) { string propName = prop.Name; string auth = authAttr.Name; _dict.Add(propName, auth); } } } return _dict; } 

Para obtener todos los atributos de una propiedad en un diccionario, usa esto:

 typeof(Book) .GetProperty("Name") .GetCustomAttributes(false) .ToDictionary(a => a.GetType().Name, a => a); 

recuerde cambiar a falso en verdadero si también desea incluir atributos heredados.

SI solo quiere un valor de atributo específico Por ejemplo, atributo de visualización, puede usar el siguiente código.

 var pInfo = typeof(Book).GetProperty("Name") .GetCustomAttribute(); var name = pInfo.Name; 

He resuelto problemas similares escribiendo un Ayudante de atributo de propiedad de extensión genérica:

 using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; public static class AttributeHelper { public static TValue GetPropertyAttributeValue( Expression> propertyExpression, Func valueSelector) where TAttribute : Attribute { var expression = (MemberExpression) propertyExpression.Body; var propertyInfo = (PropertyInfo) expression.Member; var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() as TAttribute; return attr != null ? valueSelector(attr) : default(TValue); } } 

Uso:

 var author = AttributeHelper.GetPropertyAttributeValue(prop => prop.Name, attr => attr.Author); // author = "AuthorName" 

Puede usar GetCustomAttributesData() y GetCustomAttributes() :

 var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData(); var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false); 

Si quiere decir “para los atributos que toman un parámetro, enumere los nombres de los atributos y el valor del parámetro”, entonces esto es más fácil en .NET 4.5 a través de la API CustomAttributeData :

 using System.Collections.Generic; using System.ComponentModel; using System.Reflection; public static class Program { static void Main() { PropertyInfo prop = typeof(Foo).GetProperty("Bar"); var vals = GetPropertyAttributes(prop); // has: DisplayName = "abc", Browsable = false } public static Dictionary GetPropertyAttributes(PropertyInfo property) { Dictionary attribs = new Dictionary(); // look for attributes that takes one constructor argument foreach (CustomAttributeData attribData in property.GetCustomAttributesData()) { if(attribData.ConstructorArguments.Count == 1) { string typeName = attribData.Constructor.DeclaringType.Name; if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9); attribs[typeName] = attribData.ConstructorArguments[0].Value; } } return attribs; } } class Foo { [DisplayName("abc")] [Browsable(false)] public string Bar { get; set; } } 
 private static Dictionary GetAuthors() { return typeof(Book).GetProperties() .SelectMany(prop => prop.GetCustomAttributes()) .OfType() .ToDictionary(attribute => attribute.Name, attribute => attribute.Name); } 
 public static class PropertyInfoExtensions { public static TValue GetAttributValue(this PropertyInfo prop, Func value) where TAttribute : Attribute { var att = prop.GetCustomAttributes( typeof(TAttribute), true ).FirstOrDefault() as TAttribute; if (att != null) { return value(att); } return default(TValue); } } 

Uso:

  //get class properties with attribute [AuthorAttribute] var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute))); foreach (var prop in props) { string value = prop.GetAttributValue((AuthorAttribute a) => a.Name); } 

o:

  //get class properties with attribute [AuthorAttribute] var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute))); IList values = props.Select(prop => prop.GetAttributValue((AuthorAttribute a) => a.Name)).Where(attr => attr != null).ToList(); 

Nigromancia
Para aquellos que todavía tienen que mantener .NET 2.0, o aquellos que quieren hacerlo sin LINQ:

 public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t) { object[] objs = mi.GetCustomAttributes(t, true); if (objs == null || objs.Length < 1) return null; return objs[0]; } public static T GetAttribute(System.Reflection.MemberInfo mi) { return (T)GetAttribute(mi, typeof(T)); } public delegate TResult GetValue_t(T arg1); public static TValue GetAttributValue(System.Reflection.MemberInfo mi, GetValue_t value) where TAttribute : System.Attribute { TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true); TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0]; // TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute)); if (att != null) { return value(att); } return default(TValue); } 

Ejemplo de uso:

 System.Reflection.FieldInfo fi = t.GetField("PrintBackground"); wkHtmlOptionNameAttribute att = GetAttribute(fi); string name = GetAttributValue(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;}); 

o simplemente

 string aname = GetAttributValue(fi, a => a.Name ); 
 foreach (var p in model.GetType().GetProperties()) { var valueOfDisplay = p.GetCustomAttributesData() .Any(a => a.AttributeType.Name == "DisplayNameAttribute") ? p.GetCustomAttribute().DisplayName : p.Name; } 

En este ejemplo, utilicé DisplayName en lugar de Author porque tiene un campo llamado ‘DisplayName’ para mostrar con un valor.

Aquí hay algunos métodos estáticos que puede usar para obtener MaxLength o cualquier otro atributo.

 using System; using System.Linq; using System.Reflection; using System.ComponentModel.DataAnnotations; using System.Linq.Expressions; public static class AttributeHelpers { public static Int32 GetMaxLength(Expression> propertyExpression) { return GetPropertyAttributeValue(propertyExpression,attr => attr.Length); } //Optional Extension method public static Int32 GetMaxLength(this T instance,Expression> propertyExpression) { return GetMaxLength(propertyExpression); } //Required generic method to get any property attribute from any class public static TValue GetPropertyAttributeValue(Expression> propertyExpression,Func valueSelector) where TAttribute : Attribute { var expression = (MemberExpression)propertyExpression.Body; var propertyInfo = (PropertyInfo)expression.Member; var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute; if (attr==null) { throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name); } return valueSelector(attr); } } 

Usando el método estático …

 var length = AttributeHelpers.GetMaxLength(x => x.PlayerName); 

O usando el método de extensión opcional en una instancia …

 var player = new Player(); var length = player.GetMaxLength(x => x.PlayerName); 

O usando el método estático completo para cualquier otro atributo (StringLength, por ejemplo) …

 var length = AttributeHelpers.GetPropertyAttributeValue(prop => prop.PlayerName,attr => attr.MaximumLength); 

Inspirado por la respuesta de Mikael Engver.

para obtener el atributo de enum, estoy usando:

  public enum ExceptionCodes { [ExceptionCode(1000)] InternalError, } public static (int code, string message) Translate(ExceptionCodes code) { return code.GetType() .GetField(Enum.GetName(typeof(ExceptionCodes), code)) .GetCustomAttributes(false).Where((attr) => { return (attr is ExceptionCodeAttribute); }).Select(customAttr => { var attr = (customAttr as ExceptionCodeAttribute); return (attr.Code, attr.FriendlyMessage); }).FirstOrDefault(); } 

// Utilizando

  var _message = Translate(code); 

Solo buscando el lugar correcto para poner esta pieza de código.

digamos que tiene la siguiente propiedad:

 [Display(Name = "Solar Radiation (Average)", ShortName = "SolarRadiationAvg")] public int SolarRadiationAvgSensorId { get; set; } 

Y desea obtener el valor ShortName. Tu puedes hacer:

 ((DisplayAttribute)(typeof(SensorsModel).GetProperty(SolarRadiationAvgSensorId).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName; 

O para hacerlo general:

 internal static string GetPropertyAttributeShortName(string propertyName) { return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName; }