反思 – 获取属性的属性名称和值
我有一个类,让我们叫它名为名为属性书。 有了这个属性,我有一个相关的属性。
public class Book { [Author("AuthorName")] public string Name { get; private set; } }
在我的主要方法中,我使用reflection,并希望获得每个属性的每个属性的键值对。 所以在这个例子中,我期望看到“作者”的属性名称和“AuthorName”的属性值。
问题:如何使用Reflection在我的属性上获取属性名称和值?
使用typeof(Book).GetProperties()
来获取一个PropertyInfo
实例的数组。 然后在每个PropertyInfo
上使用GetCustomAttribute()
来查看它们是否有Author
属性types。 如果他们这样做,可以从属性信息中获取属性的名称以及属性的属性值。
沿着这些行来扫描一个具有特定属性types的属性的types,并返回字典中的数据(注意,通过将types传入例程可以使其更具dynamic性):
public static Dictionary<string, string> GetAuthors() { Dictionary<string, string> _dict = new Dictionary<string, string>(); PropertyInfo[] props = typeof(Book).GetProperties(); foreach (PropertyInfo prop in props) { object[] attrs = prop.GetCustomAttributes(true); foreach (object attr in attrs) { AuthorAttribute authAttr = attr as AuthorAttribute; if (authAttr != null) { string propName = prop.Name; string auth = authAttr.Name; _dict.Add(propName, auth); } } } return _dict; }
要获取字典中属性的所有属性,请使用以下命令:
typeof(Book) .GetProperty("Name") .GetCustomAttributes(false) .ToDictionary(a => a.GetType().Name, a => a);
记住,如果你想要包含inheritance的属性,也可以改为false。
如果你只想要一个特定的属性值例如显示属性,你可以使用下面的代码。
var pInfo = typeof(Book).GetProperty("Name") .GetCustomAttributes(typeof(DisplayAttribute),false) .Cast<DisplayAttribute>().FirstOrDefault(); var name = pInfo.Name;
您可以使用GetCustomAttributesData()
和GetCustomAttributes()
:
var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData(); var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);
我通过编写通用扩展属性属性助手来解决类似的问题:
using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; public static class AttributeHelper { 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; return attr != null ? valueSelector(attr) : default(TValue); } }
用法:
var authorName = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author); // authorName = "AuthorName"
如果您的意思是“对于带有一个参数的属性,列出属性名称和参数值”,那么在.NET 4.5中通过CustomAttributeData
API更容易:
using System.Collections.Generic; using System.ComponentModel; using System.Reflection; public static class Program { static void Main() { PropertyInfo prop = typeof(Foo).GetProperty("Bar"); var vals = GetPropertyAttributes(prop); // has: DisplayName = "abc", Browsable = false } public static Dictionary<string, object> GetPropertyAttributes(PropertyInfo property) { Dictionary<string, object> attribs = new Dictionary<string, object>(); // look for attributes that takes one constructor argument foreach (CustomAttributeData attribData in property.GetCustomAttributesData()) { if(attribData.ConstructorArguments.Count == 1) { string typeName = attribData.Constructor.DeclaringType.Name; if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9); attribs[typeName] = attribData.ConstructorArguments[0].Value; } } return attribs; } } class Foo { [DisplayName("abc")] [Browsable(false)] public string Bar { get; set; } }
private static Dictionary<string, string> GetAuthors() { return typeof(Book).GetProperties() .SelectMany(prop => prop.GetCustomAttributes()) .OfType<AuthorAttribute>() .ToDictionary(attribute => attribute.Name, attribute => attribute.Name); }
Necromancing。
对于那些仍然需要维护.NET 2.0的用户,或者那些不用LINQ的用户来说:
public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t) { object[] objs = mi.GetCustomAttributes(t, true); if (objs == null || objs.Length < 1) return null; return objs[0]; } public static T GetAttribute<T>(System.Reflection.MemberInfo mi) { return (T)GetAttribute(mi, typeof(T)); } public delegate TResult GetValue_t<in T, out TResult>(T arg1); public static TValue GetAttributValue<TAttribute, TValue>(System.Reflection.MemberInfo mi, GetValue_t<TAttribute, TValue> value) where TAttribute : System.Attribute { TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true); TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0]; // TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute)); if (att != null) { return value(att); } return default(TValue); }
用法示例:
System.Reflection.FieldInfo fi = t.GetField("PrintBackground"); wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi); string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});
或干脆
string aname = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, a => a.Name );
public static class PropertyInfoExtensions { public static TValue GetAttributValue<TAttribute, TValue>(this PropertyInfo prop, Func<TAttribute, TValue> value) where TAttribute : Attribute { var att = prop.GetCustomAttributes( typeof(TAttribute), true ).FirstOrDefault() as TAttribute; if (att != null) { return value(att); } return default(TValue); } }
用法:
//get class properties with attribute [AuthorAttribute] var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute))); foreach (var prop in props) { string value = prop.GetAttributValue((AuthorAttribute a) => a.Name); }
要么:
//get class properties with attribute [AuthorAttribute] var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute))); IList<string> values = props.Select(prop => prop.GetAttributValue((AuthorAttribute a) => a.Name)).Where(attr => attr != null).ToList();
foreach (var p in model.GetType().GetProperties()) { var valueOfDisplay = p.GetCustomAttributesData() .Any(a => a.AttributeType.Name == "DisplayNameAttribute") ? p.GetCustomAttribute<DisplayNameAttribute>().DisplayName : p.Name; }
在这个例子中,我使用了DisplayName而不是Author,因为它有一个名为'DisplayName'的字段用值来显示。
这里有一些静态方法可以用来获取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);
灵感来自Mikael Engver的回答。