2009-12-15 8 views
21

Jeśli zastosuję atrybuty do klasy częściowej za pomocą MetadataType attribute, atrybuty te nie zostaną znalezione przez Attribute.IsDefined(). Ktoś wie dlaczego, lub co robię źle?Funkcja Attribute.IsDefined nie wyświetla atrybutów zastosowanych w klasie MetadataType

Poniżej znajduje się projekt testowy, który stworzyłem do tego, ale naprawdę próbuję zastosować niestandardowe atrybuty do klasy jednostek LINQ do SQL - jak this answer in this question.

Dzięki!

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

sprawdzenie tego to, ja już odpowiedział na to pytanie tutaj http://stackoverflow.com/a/24757520/3050647 – elia07

+0

to check to, już odpowiedziałem na to pytanie tutaj http://stackoverflow.com/a/24757520/3050647 – elia07

Odpowiedz

22

Atrybut MetadataType jest używany do określenia pomóc określić dodatkowe informacje na temat obiektu danych. Aby uzyskać dostęp do dodatkowych atrybutów, należy wykonać następujące czynności:

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

Obejmuje to również przykładowy atrybut pokazujący sposób wyodrębniania dodanych informacji.

+1

Awesome - thanks Adam. Oto kolejna pomocna strona: http://www.jarrettmeyer.com/2009/07/using-data-annotations-with-metadata.html Ciągle zastanawiam się, z których bibliotek można korzystać w MetadataType? Aby znaleźć atrybuty zdefiniowane w klasie MetadataType, naprawdę trzeba ich szukać i wydaje się, że nie wszystkie standardowe biblioteki .NET to zrobiłyby. Podobno MetadataType jest używany z ASP.NET - czy istnieją inne standardowe miejsca? W każdym razie, dzięki jeszcze raz. – shaunmartin

+0

Nie jestem pewien, czy istnieją standardowe miejsca, czy nie. Większość opisu samej klasy koncentruje się wokół użycia z nowym wsparciem obiektu danych (np. Struktura Entity, LINQ do SQL itp.). Byłoby to najbardziej sensowne, ponieważ pozwala na dodanie dodatkowych atrybutów walidacji. –

3

Miałem podobną sytuację. Skończyło się na tym, że napisałem następującą metodę rozszerzenia. Chodzi o to, aby ukryć abstrakcję szukania w 2 miejscach (główna klasa i klasa metadanych).

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

Użyłem tego, ale Przełączono z rozszerzenia PropertyInfo na rozszerzenie MemberInfo - linia pi.DeclaringType.GetSingleAttribute nie została skompilowana bez przełączenia do MemberInfo. –

0

Moje rozwiązanie do ogólnego zastosowania. Uzyskaj atrybut nieruchomości, której szukasz. Zwraca wartość null, jeśli nie zostanie znaleziony.

Jeśli zostanie znaleziony, zwraca sam atrybut. Abyś mógł mieć dostęp do właściwości wewnątrz atrybutu, jeśli tak.

Nadzieja na tę pomoc.

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

Przy następujących klas:

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

Musiałem dostać się sprawdzić, czy Key zostało zdefiniowane na nieruchomości dla Person klasie. Następnie musiałem uzyskać wartość nieruchomości. Korzystanie odpowiedź @AdamGrid, I zmodyfikowany kod tak, aby uzyskać to:

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."); 
} 
Powiązane problemy