2009-12-15 12 views
21

Se si applicano attributi a una classe parziale tramite MetadataType attribute, tali attributi non vengono trovati tramite Attribute.IsDefined(). Qualcuno sa perché, o cosa sto facendo male?Attribute.IsDefined non visualizza gli attributi applicati con la classe MetadataType

Di seguito è riportato un progetto di test che ho creato per questo, ma sto davvero cercando di applicare gli attributi personalizzati a una classe di entità LINQ to SQL, ad esempio this answer in this question.

Grazie!

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

controllo questo questo fuori, ho già risposto a questa domanda qui http://stackoverflow.com/a/24757520/3050647 – elia07

+0

controllo questo questo, ho già risposto a questa domanda qui http://stackoverflow.com/a/24757520/3050647 – elia07

risposta

22

L'attributo MetadataType viene utilizzato per specificare aiutare specificare le informazioni aggiuntive sull'oggetto dati. Per accedere agli attributi aggiuntivi che si avrebbe bisogno di fare qualcosa di simile al seguente:

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

Questo include anche un attributo di esempio per mostrare come estrarre informazioni che è stato aggiunto.

+1

Impressionante - grazie Adam. Ecco un'altra pagina utile: http://www.jarrettmeyer.com/2009/07/using-data-annotations-with-metadata.html Una cosa che mi chiedo ancora quali librerie è possibile utilizzare con MetadataType? Per trovare gli attributi definiti in una classe MetadataType, è necessario cercarli e sembra che non tutte le librerie .NET standard possano farlo. Apparentemente MetadataType è usato con ASP.NET - ci sono altri posti standard? Comunque, grazie ancora. – shaunmartin

+0

Non sono sicuro che ci siano posti standard o no. La maggior parte della descrizione per la classe è incentrata sull'utilizzo del nuovo supporto per gli oggetti dati (es. Entity Framework, LINQ to SQL, ecc.). Ciò sarebbe più sensato in quanto consente l'aggiunta di ulteriori attributi di convalida. –

3

Ho avuto una situazione simile. Ho finito per scrivere il seguente metodo di estensione per questo. L'idea è di nascondere l'astrazione del guardare in 2 luoghi (classe principale e classe dei metadati).

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

L'ho usato, ma è passato dall'estensione di PropertyInfo all'estensione di MemberInfo - la riga pi.DeclaringType.GetSingleAttribute non è stata compilata senza passare a MemberInfo. –

0

La mia soluzione per uso generico. Ottieni l'attributo la proprietà che stai cercando. Restituisce null se non trovato.

Se trovato, restituisce l'attributo stesso. In questo modo puoi avere accesso alle proprietà all'interno dell'attributo se vuoi.

Speranze questo aiuto.

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

Dati i seguenti classi:

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

avevo bisogno di vedere se Key è stato definito su una proprietà per Person di classe. Ho quindi avuto bisogno di ottenere il valore della proprietà. Utilizzando risposta @AdamGrid, ho modificato il codice come questo per farlo:

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