【问题标题】:Attribute.IsDefined doesn't see attributes applied with MetadataType classAttribute.IsDefined 看不到应用于 MetadataType 类的属性
【发布时间】:2009-12-15 21:28:59
【问题描述】:

如果我通过MetadataType attribute 将属性应用于部分类,则无法通过Attribute.IsDefined() 找到这些属性。有人知道为什么,或者我做错了什么吗?

下面是我为此创建的一个测试项目,但我真的在尝试将自定义属性应用于 LINQ to SQL 实体类 - 例如 this answer in this question

谢谢!

using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

namespace MetaDataTest
{
    class Program
    {
        static void Main(string[] args)
        {
            PropertyInfo[] properties = typeof(MyTestClass).GetProperties();

            foreach (PropertyInfo propertyInfo in properties)
            {
                Console.WriteLine(Attribute.IsDefined(propertyInfo, typeof(MyAttribute)));
                Console.WriteLine(propertyInfo.IsDefined(typeof(MyAttribute), true));
                Console.WriteLine(propertyInfo.GetCustomAttributes(true).Length);

                // Displays:
                // False
                // False
                // 0
            }

            Console.ReadLine();
        }
    }

    [MetadataType(typeof(MyMeta))]
    public partial class MyTestClass
    {
        public string MyField { get; set; }
    }

    public class MyMeta
    {
        [MyAttribute()]
        public string MyField { get; set; }
    }

    [AttributeUsage(AttributeTargets.All)]
    public class MyAttribute : System.Attribute
    {
    }
}

【问题讨论】:

标签: c# linq-to-sql attributes metadata custom-attributes


【解决方案1】:

MetadataType属性用于指定帮助指定数据对象的附加信息。要访问其他属性,您需要执行以下操作:

using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

namespace MetaDataTest
{
    class Program
    {
        static void Main(string[] args)
        {
            MetadataTypeAttribute[] metadataTypes = typeof(MyTestClass).GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray();
            MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault();

            if (metadata != null)
            {
                PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();

                foreach (PropertyInfo propertyInfo in properties)
                {
                    Console.WriteLine(Attribute.IsDefined(propertyInfo, typeof(MyAttribute)));
                    Console.WriteLine(propertyInfo.IsDefined(typeof(MyAttribute), true));
                    Console.WriteLine(propertyInfo.GetCustomAttributes(true).Length);
                    RequiredAttribute attrib = (RequiredAttribute)propertyInfo.GetCustomAttributes(typeof(RequiredAttribute), true)[0];
                    Console.WriteLine(attrib.ErrorMessage);
                }

                // Results:
                // True
                // True
                // 2
                // MyField is Required
            }

            Console.ReadLine();
        }
    }

    [MetadataType(typeof(MyMeta))]
    public partial class MyTestClass
    {
        public string MyField { get; set; }
    }

    public class MyMeta
    {
        [MyAttribute()]
        [Required(ErrorMessage="MyField is Required")]
        public string MyField { get; set; }
    }

    [AttributeUsage(AttributeTargets.All)]
    public class MyAttribute : System.Attribute
    {
    }
}

这还包括一个示例属性,用于显示如何提取添加的信息。

【讨论】:

  • 太棒了 - 谢谢亚当。这是另一个有用的页面:jarrettmeyer.com/2009/07/… 我仍然想知道的一件事是您可以将 MetadataType 与哪些库一起使用?要查找在 MetadataType 类中定义的属性,您确实必须查找它们,而且似乎并非所有标准 .NET 库都会这样做。显然 MetadataType 与 ASP.NET 一起使用 - 还有其他标准的地方吗?无论如何,再次感谢。
  • 我不确定是否有标准的地方。对类本身的大部分描述都围绕着使用新的数据对象支持(即实体框架、LINQ to SQL 等)。这将是最有意义的,因为它允许添加额外的验证属性。
【解决方案2】:

我也遇到过类似的情况。我最终为它编写了以下扩展方法。 这个想法是隐藏在 2 个地方(主类和元数据类)查找的抽象。

    static public Tattr GetSingleAttribute<Tattr>(this PropertyInfo pi, bool Inherit = true) where Tattr : Attribute
    {
        var attrs = pi.GetCustomAttributes(typeof(Tattr), Inherit);
        if (attrs.Length > 0)
            return (Tattr)attrs[0];
        var mt = pi.DeclaringType.GetSingleAttribute<MetadataTypeAttribute>();
        if (mt != null)
        {
            var pi2 = mt.MetadataClassType.GetProperty(pi.Name);
            if (pi2 != null)
                return pi2.GetSingleAttribute<Tattr>(Inherit);
        }
        return null;
    }

【讨论】:

  • 我使用了这个,但是从扩展 PropertyInfo 切换到扩展 MemberInfo —— 如果没有切换到 MemberInfo,pi.DeclaringType.GetSingleAttribute 行无法编译。
【解决方案3】:

我的通用解决方案。获取您要查找的属性的属性。如果没有找到,则返回 null。

如果找到,则返回属性本身。因此,如果您愿意,您可以访问属性内的属性。

希望得到帮助。

public static Attribute GetAttribute<T>(this PropertyInfo PI, T t) where T: Type
{
    var Attrs = PI.DeclaringType.GetCustomAttributes(typeof(MetadataTypeAttribute), true);
    if (Attrs.Length < 1) return null;

    var metaAttr = Attrs[0] as MetadataTypeAttribute;
    var metaProp = metaAttr.MetadataClassType.GetProperty(PI.Name);
    if (metaProp == null) return null;

    Attrs = metaProp.GetCustomAttributes(t, true);
    if (Attrs.Length < 1) return null;
    return Attrs[0] as Attribute;
}

【讨论】:

    【解决方案4】:

    给定以下类:

    public partial class Person
    {
        public int PersonId { get; set; }
    }
    
    [MetadataType(typeof(PersonMetadata))]
    public partial class Person
    {
        public partial class PersonMetadata
        {
            [Key]
            public int PersonId { get; set; }
        }
    }
    

    我需要查看 Key 是否已在 Person 类的属性上定义。然后,我需要获取财产的价值。使用@AdamGrid 答案,我修改了这样的代码来得到它:

    private static object GetPrimaryKeyValue(TEntity entity)
    {
        MetadataTypeAttribute[] metadataTypes = typeof(TEntity).GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray();
        MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault();
        if (metadata == null)
        {
            ThrowNotFound();
        }
    
        PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();
        PropertyInfo primaryKeyProperty =
            properties.SingleOrDefault(x => Attribute.GetCustomAttribute(x, typeof(KeyAttribute)) as KeyAttribute != null);
        if (primaryKeyProperty == null)
        {
            ThrowNotFound();
        }
    
        object primaryKeyValue = typeof(TEntity).GetProperties().Single(x => x.Name == primaryKeyProperty.Name).GetValue(entity);
    
        return primaryKeyValue;
    }
    
    private static void ThrowNotFound()
    {
        throw new InvalidOperationException
                ($"The type {typeof(TEntity)} does not have a property with attribute KeyAttribute to indicate the primary key. You must add that attribute to one property of the class.");
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多