检查属性是否具有属性


158

给定类中具有属性的属性-确定它是否包含给定属性的最快方法是什么?例如:

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

确定其具有“ IsIdentity”属性的最快方法是什么?

Answers:


279

没有快速的方法来检索属性。但是代码应该看起来像这样(归功于Aaronaught):

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

如果您需要检索属性属性,则

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
}

63
如果您只需要检查该属性的存在,而不从中检索任何信息,则使用Attribute.IsDefined可以消除一行代码和丑陋的数组/广播。
Aaronaught

4
我刚遇到的一些属性与其属性名称的类型不同。例如,像[NotMapped]在类中一样使用System.ComponentModel.DataAnnotations.Schema中的“ NotMapped”,但要检测到它,您必须使用Attribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo

2
使用通用重载可能更容易:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
Mojtaba,

@Qjimbo(或者可能是其他人阅读的)属性通常不带名称的“属性”部分使用,但是可以使用。约定允许您将其排除在外,因此通常实际类型的名称末尾都有Attribute,但实际上并未使用。
Jim Wolff

44

如果使用的是.NET 3.5,则可以尝试使用表达式树。比反射更安全:

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;
    }
}

7
仅供参考,您的答案已被询问。stackoverflow.com/questions/4158996/...
格雷格

12

您可以使用通用(通用)方法读取给定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;
            }

7

要更新和/或增强@Hans Passant的答案,我会将属性的检索分为扩展方法。这具有在方法GetProperty()中删除讨厌的魔术字符串的附加好处。

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();
        }
    }
}

然后您的测试减少到两行

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

7

如果您尝试在可移植类库PCL(例如我)中做到这一点,那么这就是您的操作方法:)

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());

然后,您可以根据需要检查具有此特殊属性的属性的数量。


7

现在可以使用新的C#功能以一种类型安全的方式,不用表达式树和扩展方法来完成nameof()此操作:

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

C#6中引入了nameof()


6

您可以使用Attribute.IsDefined方法

https://msdn.microsoft.com/zh-CN/library/system.attribute.isdefined(v=vs.110).aspx

if(Attribute.IsDefined(YourProperty,typeof(YourAttribute)))
{
    //Conditional execution...
}

您可以提供您专门寻找的属性,也可以使用反射来遍历所有属性,例如:

PropertyInfo[] props = typeof(YourClass).GetProperties();

这不会编译。您不能在[YourProperty]或[YourAttribute]周围使用[]
滚动

前面的每个答案都对我遵循的类,属性和属性名称进行了假设。
弗朗西斯·穆西尼亚克

现在似乎已修复。
轧辊

2

这是一个很老的问题,但是我用过

我的方法具有此参数,但可以构建:

Expression<Func<TModel, TValue>> expression

然后在此方法中:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.