反射 - 获取属性的属性名称和值

dev*_*oug 225 c# reflection propertyinfo

我有一个类,让我们用名为Name的属性调用它.使用该属性,我有一个与之关联的属性.

public class Book
{
    [Author("AuthorName")]
    public string Name
    {
        get; private set; 
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的main方法中,我正在使用反射并希望为每个属性获取每个属性的键值对.所以在这个例子中,我希望看到属性名称为"Author",属性值为"AuthorName".

问题:如何使用Reflection获取属性的属性名称和值?

Ada*_*itz 274

使用typeof(Book).GetProperties()获得的阵列PropertyInfo实例.然后GetCustomAttributes()在每个PropertyInfo上使用以查看它们中是否有任何Author属性类型.如果是,您可以从属性信息中获取属性的名称,并从属性中获取属性值.

沿着这些行扫描类型以获取具有特定属性类型的属性并返回字典中的数据(请注意,通过将类型传递到例程中可以使其更加动态化):

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 我希望我不必抛出属性. (15认同)

Mo *_*our 103

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

typeof(Book)
  .GetProperty("Name")
  .GetCustomAttributes(false) 
  .ToDictionary(a => a.GetType().Name, a => a);
Run Code Online (Sandbox Code Playgroud)

如果要包含继承属性,请记住将false更改为true.

  • 如果您只需要Author属性并希望跳过将来的强制转换,则将.OfType <AuthorAttribue>()附加到表达式而不是ToDictionary (29认同)
  • 这与Adam的解决方案实际上完全相同,但更为简洁. (3认同)
  • 当同一个属性上有两个相同类型的属性时,这不会抛出异常吗? (2认同)

max*_*pan 46

如果您只想要一个特定的属性值对于实例显示属性,您可以使用以下代码:

var pInfo = typeof(Book).GetProperty("Name")
                             .GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;
Run Code Online (Sandbox Code Playgroud)


Mik*_*ver 26

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

var author = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author);
// author = "AuthorName"
Run Code Online (Sandbox Code Playgroud)


Bro*_*ass 19

你可以使用GetCustomAttributesData()GetCustomAttributes():

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);
Run Code Online (Sandbox Code Playgroud)

  • 有什么不同? (3认同)
  • @PrimeByDesign 前者找出*如何*来实例化应用的属性。后者实际上实例化了这些属性。 (2认同)

Mar*_*ell 12

如果您的意思是"对于带有一个参数的属性,列出属性名称和参数值",那么在.NET 4.5中通过CustomAttributeDataAPI 更容易:

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; }
}
Run Code Online (Sandbox Code Playgroud)


dee*_*dee 5

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);
}
Run Code Online (Sandbox Code Playgroud)

使用泛型的示例(目标框架 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);
}
Run Code Online (Sandbox Code Playgroud)

用法

var dictionary = GetAttribute<AuthorAttribute, Book>(a => a.Name);
Run Code Online (Sandbox Code Playgroud)