2009-12-15 53 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."); 
}