如何从代码检索数据注释?(编程)
本文关键字:编程 注释 数据 代码 检索 | 更新日期: 2023-09-27 18:05:08
我使用System.ComponentModel.DataAnnotations
为我的实体框架4.1项目提供验证。
public class Player
{
[Required]
[MaxLength(30)]
[Display(Name = "Player Name")]
public string PlayerName { get; set; }
[MaxLength(100)]
[Display(Name = "Player Description")]
public string PlayerDescription{ get; set; }
}
我需要检索Display.Name
注释值以在消息中显示它,例如选择的"Player Name"是Frank.
=================================================================================
另一个例子说明为什么我可能需要检索注释:
var playerNameTextBox = new TextBox();
playerNameTextBox.MaxLength = GetAnnotation(myPlayer.PlayerName, MaxLength);
我该怎么做呢?
扩展方法:
public static T GetAttributeFrom<T>(this object instance, string propertyName) where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
return (T)property .GetCustomAttributes(attrType, false).First();
}
代码:var name = player.GetAttributeFrom<DisplayAttribute>(nameof(player.PlayerDescription)).Name;
var maxLength = player.GetAttributeFrom<MaxLengthAttribute>(nameof(player.PlayerName)).Length;
try this:
((DisplayAttribute)
(myPlayer
.GetType()
.GetProperty("PlayerName")
.GetCustomAttributes(typeof(DisplayAttribute),true)[0])).Name;
这里有一些静态方法可以用来获取MaxLength或任何其他属性。
using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
public static class AttributeHelpers {
public static Int32 GetMaxLength<T>(Expression<Func<T,string>> propertyExpression) {
return GetPropertyAttributeValue<T,string,MaxLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}
//Optional Extension method
public static Int32 GetMaxLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
return GetMaxLength<T>(propertyExpression);
}
//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
var expression = (MemberExpression)propertyExpression.Body;
var propertyInfo = (PropertyInfo)expression.Member;
var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;
if (attr==null) {
throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
}
return valueSelector(attr);
}
}
使用静态方法…
var length = AttributeHelpers.GetMaxLength<Player>(x => x.PlayerName);
或者在实例上使用可选的扩展方法…
var player = new Player();
var length = player.GetMaxLength(x => x.PlayerName);
或者为任何其他属性(例如StringLength)使用完整的静态方法…
var length = AttributeHelpers.GetPropertyAttributeValue<Player,string,StringLengthAttribute,Int32>(prop => prop.PlayerName,attr => attr.MaximumLength);
受到这里答案的启发…https://stackoverflow.com/a/32501356/324479
我就是这样做的
/// <summary>
/// Returns the DisplayAttribute of a PropertyInfo (field), if it fails returns null
/// </summary>
/// <param name="propertyInfo"></param>
/// <returns></returns>
private static string TryGetDisplayName(PropertyInfo propertyInfo)
{
string result = null;
try
{
var attrs = propertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true);
if (attrs.Any())
result = ((DisplayAttribute)attrs[0]).Name;
}
catch (Exception)
{
//eat the exception
}
return result;
}
因为https://stackoverflow.com/a/7027791/7173655上的可接受答案仍然使用魔术常量,所以我基于链接的答案共享我的代码:
扩展方法:
public static TA GetAttributeFrom<TC,TA>(string propertyName) where TA : Attribute {
return (TA)typeof(TC).GetProperty(propertyName)
.GetCustomAttributes(typeof(TA), false).SingleOrDefault();
}
不带魔法常数的使用(确保重构带来的伤害更小):
var nameMaxLength = device.GetAttributeFrom<StringLengthAttribute>(nameof(device.name)).MaximumLength;
我认为这个例子https://github.com/TeteStorm/DataAnnotationScan可以非常有用。
我只是为了在我的模型组装中获得EF使用的数据注释,但可以根据需要随意分叉和更改。
更改下面的方法hasefdataannotation并享受乐趣!
https://github.com/TeteStorm/DataAnnotationScan
private static bool HasEFDataAnnotaion(PropertyInfo[] properties)
{
return properties.ToList().Any((property) =>
{
var attributes = property.GetCustomAttributes(false);
Attribute[] attrs = System.Attribute.GetCustomAttributes(property);
return attrs.Any((attr) =>
{
return attr is KeyAttribute || attr is ForeignKeyAttribute || attr is IndexAttribute || attr is RequiredAttribute || attr is TimestampAttribute
|| attr is ConcurrencyCheckAttribute || attr is MinLengthAttribute || attr is MinLengthAttribute
|| attr is MaxLengthAttribute || attr is StringLengthAttribute || attr is TableAttribute || attr is ColumnAttribute
|| attr is DatabaseGeneratedAttribute || attr is ComplexTypeAttribute;
});
});
}
修复在这里使用MetadataTypeAttribute的元数据类
public T GetAttributeFrom<T>( object instance, string propertyName) where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
T t = (T)property.GetCustomAttributes(attrType, false).FirstOrDefault();
if (t == null)
{
MetadataTypeAttribute[] metaAttr = (MetadataTypeAttribute[])instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true);
if (metaAttr.Length > 0)
{
foreach (MetadataTypeAttribute attr in metaAttr)
{
var subType = attr.MetadataClassType;
var pi = subType.GetField(propertyName);
if (pi != null)
{
t = (T)pi.GetCustomAttributes(attrType, false).FirstOrDefault();
return t;
}
}
}
}
else
{
return t;
}
return null;
}