给定一个类中的属性,带有属性—确定它是否包含给定属性的最快方法是什么?例如:

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

例如,确定它具有“IsIdentity”属性的最快方法是什么?


当前回答

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

其他回答

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

我的方法有这个参数,但它可以建立:

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

如果你试图在一个可移植类库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());

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

为了更新和/或增强@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));

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

如果你正在使用。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;
    }
}

这更安全,因为它绑定到属性Id本身。如果属性名称更改,则在编译时失败。

而反射被绑定到字符串“Id”,如果属性名称发生变化,它不会编译失败,只会在执行该代码时失败。 现代版本的c#可以通过使用name (MyClass.Id)来代替“Id”来避免这种情况。