反思 – 获取属性的属性名称和值

我有一个类,让我们叫它名为名为属性书。 有了这个属性,我有一个相关的属性。

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的回答。