2010-01-12 22 views
115

Dada una propiedad en una clase, con atributos: ¿cuál es la forma más rápida de determinar si contiene un atributo determinado? Por ejemplo:Compruebe si la propiedad tiene el atributo

[IsNotNullable] 
    [IsPK] 
    [IsIdentity] 
    [SequenceNameAttribute("Id")] 
    public Int32 Id 
    { 
     get 
     { 
      return _Id; 
     } 
     set 
     { 
      _Id = value; 
     } 
    } 

¿Cuál es el método más rápido para determinar que, por ejemplo, que tiene la "IsIdentity" atribuir?

Respuesta

209

No hay una forma rápida de recuperar atributos. Pero el código debería tener este aspecto (crédito a Aaronaught):

var t = typeof(YourClass); 
var pi = t.GetProperty("Id"); 
var hasIsIdentity = Attribute.IsDefined(pi, typeof(IsIdentity)); 

Si necesita recuperar las propiedades de atributos a continuación

var t = typeof(YourClass); 
var pi = t.GetProperty("Id"); 
var attr = (IsIdentity[])pi.GetCustomAttributes(typeof(IsIdentity), false); 
if (attr.Length > 0) { 
    // Use attr[0], you'll need foreach on attr if MultiUse is true 
} 
+52

Si solo necesita verificar la existencia del atributo y no recuperar ninguna información del mismo, usar 'Attribute.IsDefined' eliminará una línea de código y las feas matrices/moldes. – Aaronaught

38

Si está utilizando .NET 3.5 se puede tratar con árboles de expresión. Es más seguro que la reflexión:

class CustomAttribute : Attribute { } 

class Program 
{ 
    [Custom] 
    public int Id { get; set; } 

    static void Main() 
    { 
     Expression<Func<Program, int>> expression = p => p.Id; 
     var memberExpression = (MemberExpression)expression.Body; 
     bool hasCustomAttribute = memberExpression 
      .Member 
      .GetCustomAttributes(typeof(CustomAttribute), false).Length > 0; 
    } 
} 
+6

FYI se ha formulado una pregunta acerca de su respuesta. http://stackoverflow.com/questions/4158996/why-are-expression-trees-safer-than-reflection – Greg

11

Se puede utilizar un método común (genérico) para leer el atributo durante un determinado MemberInfo

public static bool TryGetAttribute<T>(MemberInfo memberInfo, out T customAttribute) where T: Attribute { 
       var attributes = memberInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault(); 
       if (attributes == null) { 
        customAttribute = null; 
        return false; 
       } 
       customAttribute = (T)attributes; 
       return true; 
      } 
5

Para actualizar y/o mejorar la respuesta por @Hans Passant lo haría separa la recuperación de la propiedad en un método de extensión. Esto tiene la ventaja añadida de la eliminación de la cadena mágica desagradable en el GetProperty método()

public static class PropertyHelper<T> 
{ 
    public static PropertyInfo GetProperty<TValue>(
     Expression<Func<T, TValue>> selector) 
    { 
     Expression body = selector; 
     if (body is LambdaExpression) 
     { 
      body = ((LambdaExpression)body).Body; 
     } 
     switch (body.NodeType) 
     { 
      case ExpressionType.MemberAccess: 
       return (PropertyInfo)((MemberExpression)body).Member; 
      default: 
       throw new InvalidOperationException(); 
     } 
    } 
} 

Su prueba se reduce entonces a dos líneas

var property = PropertyHelper<MyClass>.GetProperty(x => x.MyProperty); 
Attribute.IsDefined(property, typeof(MyPropertyAttribute)); 
5

Si usted está tratando de hacer que en una clase portátil biblioteca PCL (como yo), entonces aquí es cómo puede hacerlo :)

public class Foo 
{ 
    public string A {get;set;} 

    [Special] 
    public string B {get;set;} 
} 

var type = typeof(Foo); 

var specialProperties = type.GetRuntimeProperties() 
    .Where(pi => pi.PropertyType == typeof (string) 
     && pi.GetCustomAttributes<Special>(true).Any()); 

a continuación, puede comprobar el número de propiedades que tienen esta propiedad especial si es necesario.

1

Ésta es una pregunta bastante viejo pero utilizado

Mi método tiene este parámetro pero podría ser construida:

Expression<Func<TModel, TValue>> expression 

Luego, en el método siguiente:

System.Linq.Expressions.MemberExpression memberExpression 
     = expression.Body as System.Linq.Expressions.MemberExpression; 
Boolean hasIdentityAttr = System.Attribute 
     .IsDefined(memberExpression.Member, typeof(IsIdentity)); 
1

Esto puede ahora se hace sin árboles de expresión y métodos de extensión de una manera segura tipo con la nueva característica de C# nameof() así:

Attribute.IsDefined(typeof(YourClass).GetProperty(nameof(YourClass.Id)), typeof(IsIdentity)); 
Cuestiones relacionadas