2009-12-15 54 views
21

如果我通过MetadataType attribute将属性应用于部分类,则通过Attribute.IsDefined()找不到这些属性。任何人都知道为什么,或者我做错了什么?属性。IsDefined未看到应用于MetadataType类的属性

下面是我为此创建的一个测试项目,但我真的试图将自定义属性应用于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 
    { 
    } 
} 
+0

支票本了这一点,我已经回答了这里 http://stackoverflow.com/a/24757520/3050647 – elia07 2014-07-15 11:58:28

+0

检查这个这个问题这一点,我已经在这里回答了这个问题 http://stackoverflow.com/a/24757520/3050647 – elia07 2014-07-15 12:17:19

回答

22

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

这还包括示例属性以显示如何提取已添加的信息。

+1

真棒 - 感谢亚当。这里是另一个有用的页面: http://www.jarrettmeyer.com/2009/07/using-data-annotations-with-metadata.html 我还在想的一件事是哪些库可以使用MetadataType?要找到在MetadataType类中定义的属性,你真的必须寻找它们,而且好像并非所有的标准.NET库都会这样做。显然,MetadataType与ASP.NET一起使用 - 还有其他标准位置吗?无论如何,再次感谢。 – shaunmartin 2009-12-15 23:09:36

+0

我不确定是否有标准的地方。大多数类的描述本身都围绕着新的Data对象支持(即实体框架,LINQ to SQL等)的使用。这样做最有意义,因为它允许添加额外的验证属性。 – 2009-12-16 13:09:02

3

我有类似的情况。我最终为它写了下面的扩展方法。 这个想法是隐藏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; 
    } 
+2

我使用过这种方法,但是从扩展PropertyInfo切换到扩展MemberInfo - pi.DeclaringType.GetSingleAttribute行没有切换到MemberInfo时没有编译。 – 2012-08-22 16:59:49

0

我的通用解决方案。获取您正在查找的属性的属性。如果未找到,则返回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; 
} 
0

考虑以下类:

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."); 
}