简体   繁体   English

如何获取元数据自定义属性?

[英]How to get metadata custom attributes?

I have a class that defines data annotations at class level. 我有一个类在类级别定义数据注释 The meta data class has custom attributes associated with it, along with the usual DisplayName, DisplayFormat etc. 元数据类具有与之关联的自定义属性,以及通常的DisplayName,DisplayFormat等。

public class BaseMetaData
{
    [DisplayName("Id")]
    public object Id { get; set; }

    [DisplayName("Selected")]
    [ExportItem(Exclude = true)]
    public object Selected { get; set; }
}

[MetadataType(typeof(BaseMetaData))]
public class BaseViewModel
{
    public int Id { get; set; }
    public bool Selected { get; set; }

Given a type T , how can I retrieve the custom attributes from the meta data class? 给定类型T ,如何从元数据类中检索自定义属性? The attempt below would not work as the metadata properties are from the BaseViewModel rather than the BaseMetaData class. 下面的尝试不起作用,因为元数据属性来自BaseViewModel而不是BaseMetaData类。

Needs to work generically ie can't do typeof(BaseMetaData).GetProperty(e.PropertyName). 需要一般工作,即不能做typeof(BaseMetaData).GetProperty(e.PropertyName)。 Wondering if there is a way of getting the MetadataType from the class then it would make it possible. 想知道是否有从类中获取MetadataType的方法,那么它将使其成为可能。

var type = typeof (T);
var metaData = ModelMetadataProviders.Current.GetMetadataForType(null, type);

var propertMetaData = metaData.Properties
    .Where(e =>
    {
        var attribute = type.GetProperty(e.PropertyName)
            .GetCustomAttributes(typeof(ExportItemAttribute), false)
            .FirstOrDefault() as ExportItemAttribute;
        return attribute == null || !attribute.Exclude;
    })
    .ToList();

Found a solution by using the type of MetadataTypeAttribute to get the custom attributes. 通过使用MetadataTypeAttribute类型获取自定义属性找到解决方案。

var type = typeof (T);
var metadataType = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true)
    .OfType<MetadataTypeAttribute>().FirstOrDefault();
var metaData = (metadataType != null)
    ? ModelMetadataProviders.Current.GetMetadataForType(null, metadataType.MetadataClassType)
    : ModelMetadataProviders.Current.GetMetadataForType(null, type);

var propertMetaData = metaData.Properties
    .Where(e =>
    {
        var attribute = metaData.ModelType.GetProperty(e.PropertyName)
            .GetCustomAttributes(typeof(ExportItemAttribute), false)
            .FirstOrDefault() as ExportItemAttribute;
        return attribute == null || !attribute.Exclude;
    })
    .ToList();

Have you tried just doing this, 你有没有试过这样做,

public class BaseViewModel
{
    [DisplayName("Id")]
    public int Id { get; set; }

    [DisplayName("Selected")]
    [ExportItem(Exclude = true)]
    public bool Selected { get; set; }
}

You can then use a variation of your code, 然后,您可以使用代码的变体,

var type = typeof(T);    
var propertyMetaData = type.GetProperties()
    .Select(property => 
        property.GetCustomAttributes(typeof(ExportItemAttribute), false)
                .FirstOrDefault() as ExportItemAttribute)
    .Where(attribute => attribute == null || !attribute.Exclude)
    .ToList();

I was looking for something similar, and looking at the class MetadataTypeAttribute, I realice that it stores the type of the Metdata class. 我正在寻找类似的东西,并查看MetadataTypeAttribute类,我实际上它存储了Metdata类的类型。 Inside that class, you can have get/set properties, or just fields (get/set properties are defined in one partial class, like autogenerated models in MVC), so, I read the fields within that metadata class, then get the atributes for the field. 在该类中,您可以拥有get / set属性,或者只有字段(get / set属性在一个分部类中定义,如MVC中的自动生成模型),因此,我读取该元数据类中的字段,然后获取属性场。 Code is: 代码是:

    using System;
    using System.Linq;
    using System.Reflection;
    using System.ComponentModel.DataAnnotations;

    namespace PruebaAtributos
    {
        // Podemos ver la definición de 'MetaDataType' en:
        // https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/MetadataTypeAttribute.cs,fb9a5881152a1584,references
        [MetadataType(typeof(ProgramMetadata))]
        partial class Program
        {
            // Campos de la clase
            public int Id { get; set; }
            public string Nombre { get; set; }
            public string Puesto { get; set; }

            static void Main(string[] args)
            {
                Type t = typeof(Program);

                // Atributos de la clase
                Console.WriteLine("--- Atributos de clase: ");
                Attribute[] attrs = Attribute.GetCustomAttributes(t);
                foreach (Attribute at in attrs)
                {
                    Console.WriteLine(at.GetType().Name);
                    if (at is MetadataTypeAttribute mdt)
                    {
                        // Nos interesa la información que contiene 'MetadataType'
                        Console.WriteLine($"--- Campos de {mdt.GetType().Name}:");

                        // Obtenemos las propiedades de la clase asociada con metadata type
                        var fields = mdt.MetadataClassType.GetFields();
                        foreach (FieldInfo fi in fields)
                        {
                            // Y mostramos los atributos asociados a cada uno de sus campos
                            var cas = fi.GetCustomAttributes(); // ca = Custom Attributes
                            Console.WriteLine($"   {fi.Name}.");
                            Console.WriteLine($"      attributos: {string.Join(", ", cas.Select(a => a.GetType().Name))}");

                            // Ahora consultamos la propiedad que deseamos de cada atributo conocido:

                            // Para consultar un attributo específico:
                            //DisplayAttribute da = (DisplayAttribute)ca.FirstOrDefault(a => a.GetType() == typeof(DisplayAttribute));
                            //if (da != null)
                            //{
                            //    Console.WriteLine($"   {da.GetType().Name}: {da.Name}");
                            //}
                            string desc;
                            foreach (var fa in cas) // fa = Field Attribute
                            {
                                if (fa is ExportarAttribute exp)
                                {
                                    // Conocemos las propiedades específicas de este 
                                    desc = $"{exp.GetType().Name}.exportar: {exp.exportar}";
                                }
                                else if (fa is MostrarAUsuario mau)
                                {
                                    desc = $"{mau.GetType().Name}.mostrar: {mau.mostrar}";
                                }
                                else if (fa is DisplayAttribute da)
                                {
                                    desc = $"{da.GetType().Name}.Name: {da.Name}";
                                }
                                else
                                {
                                    desc = fa.GetType().Name;
                                }
                                Console.WriteLine($"      {desc}");
                            }
                        }
                    }
                }
            }
        }

        // Attributos personalizados
        [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
        class MostrarAUsuario : Attribute
        {
            public readonly bool mostrar;
            public MostrarAUsuario(bool mostrar = true)
            {
                this.mostrar = mostrar;
            }
        };

        class ExportarAttribute : Attribute
        {
            public readonly bool exportar;
            public ExportarAttribute(bool exportar = true)
            {
                this.exportar = exportar;
            }
        }

        public class ProgramMetadata
        {
            // Display pertenece a MVC: System.ComponentModel.DataAnnotations
            [Display(Name = "Identificador"), MostrarAUsuario(false), Exportar(false), Phone]
            public int Id;
            [Display(Name = "Nombre completo"), MostrarAUsuario]
            public int Nombre;
            [Display(Name = "Puesto de trabajo"), Exportar]
            public int Puesto;
        }
    }

Result I see is: 结果我看到的是: 控制台结果

Based on the other answers, i'm successed to get the DisplayName attribute from MetadataType class in this way: 基于其他答案,我成功地以这种方式从MetadataType类获取DisplayName属性:

var metadataType = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true)
            .OfType<MetadataTypeAttribute>().FirstOrDefault();

        var metaData = (metadataType != null)
                ? ModelMetadataProviders.Current.GetMetadataForType(null, metadataType.MetadataClassType)
                : ModelMetadataProviders.Current.GetMetadataForType(null, type);

        List<string> propertyList = metaData.Properties.
            Select(x => x.DisplayName).ToList();

I offer the following solution as an alternative. 我提供以下解决方案作为替代方案。 It works with any custom attribute (this example demonstrates StringLength) and it's fast. 它适用于任何自定义属性(此示例演示StringLength)并且速度很快。 It's based on this method and this method above. 它基于这种方法和上面的方法

The MetaDataType attribute and type class: MetaDataType属性和类型类:

[MetadataType(typeof(ImportSetMetaData))]
public partial class ImportSet
{
}

public class ImportSetMetaData
{
    [StringLength(maximumLength: 32)]
    public string Segment { get; set; }

The extension methods: 扩展方法:

public static class Extension
{
    private static int? GetMaxLength<T>(Expression<Func<T, string>> propertyExpression)
    {
        int? result = GetPropertyAttributeValue<T, string, StringLengthAttribute, int?>
                (propertyExpression, attr => attr.MaximumLength);
        return result;
    }   

    public static int? GetMaxLength<T>(this T instance, Expression<Func<T, string>> propertyExpression)
    {
        return GetMaxLength<T>(propertyExpression);
    }

    private static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>
        (Expression<Func<T, TOut>> propertyExpression, Func<TAttribute, TValue> valueSelector) where TAttribute : Attribute
    {
        var expression = (MemberExpression)propertyExpression.Body;
        string mName = expression.Member.Name;
        Type type = typeof(T);
        MemberInfo member = type.GetMember(mName).FirstOrDefault();
        var attr = member.GetCustomAttribute<TAttribute>(inherit: true);
        if (attr != null)
        {
            return valueSelector(attr);
        }
        else
        {
            var mdTypeAttr = (MetadataTypeAttribute)type.GetCustomAttribute<MetadataTypeAttribute>(inherit: true);
            type = mdTypeAttr.MetadataClassType;
            member = type.GetMember(mName).FirstOrDefault();
            attr = member.GetCustomAttribute<TAttribute>(inherit: true);
            return (attr == null ? default(TValue) : valueSelector(attr));
        }
    }
}

The usage: 用法:

int n = ImportSet.GetMaxLength(x => x.Segment);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM