21 Stimmen

Attribute.IsDefined sieht keine Attribute, die mit der Klasse MetadataType angewendet werden

Wenn ich Attribute auf eine partielle Klasse über die Attribut "MetadataType werden diese Attribute nicht gefunden über Attribut.IsDefined() . Weiß jemand, warum, oder was ich falsch mache?

Unten ist ein Testprojekt, das ich dafür erstellt habe, aber ich versuche wirklich, benutzerdefinierte Attribute auf eine LINQ to SQL-Entitätsklasse anzuwenden - wie diese Antwort auf diese Frage .

Gracias.

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

23voto

Adam Gritt Punkte 2624

En MetadataType Attribut wird verwendet, um die zusätzlichen Informationen über das Datenobjekt zu spezifizieren. Um auf die zusätzlichen Attribute zuzugreifen, müssten Sie etwa wie folgt vorgehen:

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

Dazu gehört auch ein Beispielattribut, das zeigt, wie die hinzugefügten Informationen extrahiert werden können.

3voto

Rajesh Kumar Punkte 31

Ich hatte eine ähnliche Situation. Ich habe schließlich die folgende Erweiterungsmethode dafür geschrieben. Die Idee ist, die Abstraktion der Suche in 2 Orten (Hauptklasse und Metadaten-Klasse) zu verstecken.

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

0voto

s k Punkte 2988

Meine Lösung für die generische Verwendung. Holen Sie sich das Attribut die Eigenschaft, die Sie suchen. Null zurückgeben, wenn nicht gefunden.

Wenn es gefunden wird, gibt es das Attribut selbst zurück. So können Sie auf die Eigenschaften innerhalb des Attributs zugreifen, wenn Sie möchten.

Ich hoffe, das hilft.

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

0voto

CodingYoshi Punkte 23266

Gegeben sind die folgenden Klassen:

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

Ich musste herausfinden, ob Key wurde für eine Eigenschaft definiert für Person Klasse. Dann musste ich den Wert der Eigenschaft abrufen. Mit @AdamGrid Antwort, änderte ich den Code wie folgt, um es zu bekommen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X