2009-12-15 2 views
21

MetadataType attribute을 통해 부분 클래스에 특성을 적용하면 이러한 특성은 Attribute.IsDefined()을 통해 발견되지 않습니다. 누구나 왜, 또는 내가 뭘 잘못 알고있어?Attribute.IsDefined에 MetadataType 클래스에 적용된 특성이 표시되지 않습니다.

다음은 이것을 위해 만든 테스트 프로젝트이지만 LYQ-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

+0

확인이이 질문에 대답 @AdamGrid 대답을 사용하여, 나는이 같은 코드가 얻을 수정 이 질문에 이미 대답했습니다. http://stackoverflow.com/a/24757520/3050647 – elia07

답변

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

굉장 - 감사합니다. Adam. 다른 유용한 페이지가 있습니다. http://www.jarrettmeyer.com/2009/07/using-data-annotations-with-metadata.html 내가 아직도 궁금해하는 한 가지는 MetadataType을 사용할 수있는 라이브러리입니다. MetadataType 클래스에 정의 된 속성을 찾으려면 실제로 그 속성을 찾고 있어야하며, 모든 표준 .NET 라이브러리가 그렇게하는 것은 아닌 것처럼 보입니다. 분명히 MetadataType은 ASP.NET에서 사용됩니다 - 다른 표준 장소가 있습니까? 어쨌든, 다시 한번 감사드립니다. – shaunmartin

+0

표준 장소가 있는지 확실하지 않습니다. 클래스 자체에 대한 대부분의 설명은 새로운 Data 객체 지원 (즉, Entity Framework, LINQ to SQL 등)을 사용하는 방법을 중심으로 이루어집니다. 이는 추가 유효성 검사 속성을 추가 할 수 있으므로 가장 적합합니다. –

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로 전환하지 않고 컴파일되지 않았습니다. –

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

나는 KeyPerson 클래스의 속성에 정의되어 있는지 확인받을 필요가 있었다. 나는 그 때 재산의 가치를 얻을 필요가 있었다.

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."); 
} 
관련 문제