[c#] Reflection - get attribute name and value on property

I have a class, lets call it Book with a property called Name. With that property, I have an attribute associated with it.

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

In my main method, I'm using reflection and wish to get key value pair of each attribute for each property. So in this example, I'd expect to see "Author" for attribute name and "AuthorName" for the attribute value.

Question: How do I get the attribute name and value on my properties using Reflection?

This question is related to c# reflection propertyinfo

The answer is


to get attribute from enum, i'm using :

 public enum ExceptionCodes
 {
  [ExceptionCode(1000)]
  InternalError,
 }

 public static (int code, string message) Translate(ExceptionCodes code)
        {
            return code.GetType()
            .GetField(Enum.GetName(typeof(ExceptionCodes), code))
            .GetCustomAttributes(false).Where((attr) =>
            {
                return (attr is ExceptionCodeAttribute);
            }).Select(customAttr =>
            {
                var attr = (customAttr as ExceptionCodeAttribute);
                return (attr.Code, attr.FriendlyMessage);
            }).FirstOrDefault();
        }

// Using

 var _message = Translate(code);

You can use GetCustomAttributesData() and GetCustomAttributes():

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);

If you mean "for attributes that take one parameter, list the attribute-names and the parameter-value", then this is easier in .NET 4.5 via the 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; }
}

I have solved similar problems by writing a Generic Extension Property Attribute Helper:

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);
    }
}

Usage:

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

Example using generics (target framework 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);
}

Usage

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

Usage:

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

To get all attributes of a property in a dictionary use this:

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

remember to change from false to true if you want to include inheritted attributes as well.


Here are some static methods you can use to get the MaxLength, or any other attribute.

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);
}

}

Using the static method...

var length = AttributeHelpers.GetMaxLength<Player>(x => x.PlayerName);

Or using the optional extension method on an instance...

var player = new Player();
var length = player.GetMaxLength(x => x.PlayerName);

Or using the full static method for any other attribute (StringLength for example)...

var length = AttributeHelpers.GetPropertyAttributeValue<Player,string,StringLengthAttribute,Int32>(prop => prop.PlayerName,attr => attr.MaximumLength);

Inspired by the Mikael Engver's answer.


While the above most upvoted answers definitely work, I'd suggest using a slightly different approach in some cases.

If your class has multiple properties with always the same attribute and you want to get those attributes sorted into a dictionary, here is how:

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

This still uses cast but ensures that the cast will always work as you will only get the custom attributes of the type "AuthorName". If you had multiple Attributes above answers would get a cast exception.


I wrote this into a dynamic method since I use lots of attributes throughout my application. Method:

public static dynamic GetAttribute(Type objectType, string propertyName, Type attrType)
    {
        //get the property
        var property = objectType.GetProperty(propertyName);

        //check for object relation
        return property.GetCustomAttributes().FirstOrDefault(x => x.GetType() == attrType);
    }

Usage:

var objectRelAttr = GetAttribute(typeof(Person), "Country", typeof(ObjectRelationAttribute));

var displayNameAttr = GetAttribute(typeof(Product), "Category", typeof(DisplayNameAttribute));

Hope this helps anyone


Necromancing.
For those that still have to maintain .NET 2.0, or those that want to do it without 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);
}

Example usage:

System.Reflection.FieldInfo fi = t.GetField("PrintBackground");
wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi);
string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});

or simply

string aname = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, a => a.Name );

foreach (var p in model.GetType().GetProperties())
{
   var valueOfDisplay = 
       p.GetCustomAttributesData()
        .Any(a => a.AttributeType.Name == "DisplayNameAttribute") ? 
            p.GetCustomAttribute<DisplayNameAttribute>().DisplayName : 
            p.Name;
}

In this example I used DisplayName instead of Author because it has a field named 'DisplayName' to be shown with a value.


If you just want one specific Attribute value For instance Display Attribute you can use the following code:

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

Just looking for the right place to put this piece of code.

let's say you have the following property:

[Display(Name = "Solar Radiation (Average)", ShortName = "SolarRadiationAvg")]
public int SolarRadiationAvgSensorId { get; set; }

And you want to get the ShortName value. You can do:

((DisplayAttribute)(typeof(SensorsModel).GetProperty(SolarRadiationAvgSensorId).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;

Or to make it general:

internal static string GetPropertyAttributeShortName(string propertyName)
{
    return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
}