我有一个类,叫它Book,它的属性叫Name。有了这个属性,我就有了一个与之关联的属性。

public class Book
{
    [Author("AuthorName")]
    public string Name
    {
        get; private set; 
    }
}

在我的主要方法中,我使用反射,并希望获得每个属性的每个属性的键值对。因此,在本例中,我希望看到属性名为“Author”,属性值为“AuthorName”。

问:如何使用反射获取属性上的属性名和值?


当前回答

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”的字段要显示一个值。

其他回答

虽然上面得到最多好评的答案肯定有效,但我建议在某些情况下使用稍微不同的方法。

如果你的类有多个具有相同属性的属性,并且你想要将这些属性排序到字典中,下面是如何做的:

var dict = typeof(Book).GetProperties().ToDictionary(p => p.Name, p => p.GetCustomAttributes(typeof(AuthorName), false).Select(a => (AuthorName)a).FirstOrDefault());

这仍然使用强制转换,但确保强制转换始终有效,因为您将只获得“AuthorName”类型的自定义属性。 如果你有多个以上的属性,答案将得到一个强制转换异常。

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”的字段要显示一个值。

如果你只想要一个特定的属性值,例如Display Attribute,你可以使用以下代码:

var pInfo = typeof(Book).GetProperty("Name")
                             .GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;

我已经通过编写一个通用扩展属性属性助手解决了类似的问题:

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 author = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author);
// author = "AuthorName"
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);
            }

or:

 //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();