【问题标题】:Check if property has attribute检查属性是否具有属性
【发布时间】:2010-01-12 17:44:44
【问题描述】:

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

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

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

【问题讨论】:

    标签: c# performance


    【解决方案1】:

    没有快速检索属性的方法。但是代码应该是这样的(感谢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
    }
    

    【讨论】:

    • 如果你只需要检查属性是否存在,而不需要从中检索任何信息,使用Attribute.IsDefined将消除一行代码和丑陋的数组/转换。
    • 我刚刚遇到的问题是某些属性的属性名称类型不同。例如 System.ComponentModel.DataAnnotations.Schema 中的“NotMapped”在类中用作[NotMapped],但要检测它,您必须使用Attribute.IsDefined(pi, typeof(NotMappedAttribute))
    • 可能更容易使用泛型重载:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
    • @Qjimbo(或者可能是其他人正在阅读) 属性通常在其名称中不带“属性”部分的情况下使用,但也可以。约定允许您将其排除在外,因此通常实际类型的名称末尾确实有 Attribute,但只是不使用。
    【解决方案2】:

    如果您使用的是 .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;
        }
    }
    

    【讨论】:

    【解决方案3】:

    现在可以使用新的 C# 功能 nameof() 以类型安全的方式在没有表达式树和扩展方法的情况下完成此操作,如下所示:

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

    nameof() 在 C# 6 中引入

    【讨论】:

      【解决方案4】:

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

        你可以使用Attribute.IsDefined方法

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

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

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

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

        【讨论】:

        • 这不会编译。您不能在 YourProperty 或 YourAttribute 周围使用 []
        • 之前的每个答案都使用了我遵循的类、属性和属性名称的假设。
        • 现已修复。
        【解决方案6】:

        如果您尝试在可移植类库 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】:

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

          【讨论】:

            【解决方案8】:

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

            我的方法有这个参数但是可以构建:

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

            【讨论】:

              猜你喜欢
              • 2020-07-09
              • 2020-06-03
              • 1970-01-01
              • 2013-12-26
              • 2022-01-26
              • 1970-01-01
              • 2014-05-10
              • 2019-04-30
              • 1970-01-01
              相关资源
              最近更新 更多