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

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

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

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


当前回答

private static Dictionary<string, string> GetAuthors()
{
    return typeof(Book).GetProperties()
        .SelectMany(prop => prop.GetCustomAttributes())
        .OfType<AuthorAttribute>()
        .ToDictionary(a => a.GetType().Name.Replace("Attribute", ""), a => a.Name);
}

使用泛型的示例(目标框架4.5)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

private static Dictionary<string, string> GetAttribute<TAttribute, TType>(
    Func<TAttribute, string> valueFunc)
    where TAttribute : Attribute
{
    return typeof(TType).GetProperties()
        .SelectMany(p => p.GetCustomAttributes())
        .OfType<TAttribute>()
        .ToDictionary(a => a.GetType().Name.Replace("Attribute", ""), valueFunc);
}

使用

var dictionary = GetAttribute<AuthorAttribute, Book>(a => a.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 );

如果你想获得具有自定义属性的属性,那么请尝试以下方法:

IEnumerable propertyInfos = properties.GetType().GetProperties();

PropertyInfo p = PropertyInfo。Where(x => x. getcustomattribute () != null);

这里有一些静态方法,可以用来获取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回答的启发。

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

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

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

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

要获取一个属性在字典中的所有属性,请使用以下命令:

typeof(Book)
  .GetProperty("Name")
  .GetCustomAttributes(false) 
  .ToDictionary(a => a.GetType().Name, a => a);

如果您还想包含继承的属性,请记住从false更改为true。