我有一个在课程级别定义数据注释的课程。元数据类具有与之关联的自定义属性,以及通常的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; }
如果类型 T ,如何从元数据类中检索自定义属性?下面的尝试不起作用,因为元数据属性来自 BaseViewModel 而不是 BaseMetaData 类。
需要一般工作,即不能做typeof(BaseMetaData).GetProperty(e.PropertyName)。想知道是否有从类中获取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();
答案 0 :(得分:15)
使用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();
答案 1 :(得分:0)
你有没有试过这样做,
public class BaseViewModel
{
[DisplayName("Id")]
public int Id { get; set; }
[DisplayName("Selected")]
[ExportItem(Exclude = true)]
public bool Selected { get; set; }
}
然后,您可以使用代码的变体
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();
答案 2 :(得分:0)
我一直在寻找类似的东西,然后查看类MetadataTypeAttribute,我意识到它存储了Metdata类的类型。在该类内部,您可以具有get / set属性,也可以仅具有字段(在一个局部类中定义了get / set属性,例如MVC中的自动生成的模型),因此,我读取了该元数据类中的字段,然后获取其属性场。代码是:
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;
}
}
答案 3 :(得分:0)
基于其他答案,我成功地从MetadataType类获取DisplayName属性 通过这种方式:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(
context =>
new FabricTransportServiceRemotingListener(
context,
serviceRemotingMessageHandler: new MiddlewareServiceRemotingMessageDispatcher(
context,
this,
middlewareAction: MiddlewareAction,
serviceRemotingMessageBodyFactory: new JsonMessageFactory()),
serializationProvider: new ServiceRemotingJsonSerializationProvider()))
};
}
答案 4 :(得分:0)
我提供以下解决方案作为替代。它可以与任何自定义属性一起使用(此示例演示了StringLength),并且速度很快。它基于上面的method和上面的method。
MetaDataType属性和类型类:
[MetadataType(typeof(ImportSetMetaData))]
public partial class ImportSet
{
}
public class ImportSetMetaData
{
[StringLength(maximumLength: 32)]
public string Segment { get; set; }
扩展方法:
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));
}
}
}
用法:
int n = ImportSet.GetMaxLength(x => x.Segment);