340

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?

  • whats happening when you are trying to access property's on that object through reflection , are you stuck somewhere or do you want code for reflection – kobe Jul 09 '11 at 21:50

16 Answers16

397

Use typeof(Book).GetProperties() to get an array of PropertyInfo instances. Then use GetCustomAttributes() on each PropertyInfo to see if any of them have the Author Attribute type. If they do, you can get the name of the property from the property info and the attribute values from the attribute.

Something along these lines to scan a type for properties that have a specific attribute type and to return data in a dictionary (note that this can be made more dynamic by passing types into the routine):

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;
}
Taran
  • 12,822
  • 3
  • 43
  • 47
Adam Markowitz
  • 12,919
  • 3
  • 29
  • 21
  • 20
    I was hoping that I won't have to cast the attribute. –  Jul 09 '11 at 22:14
  • prop.GetCustomAttributes(true) only returns an object[]. If you don't want to cast then you could use reflection on the attribute instances themselves. – Adam Markowitz Jul 09 '11 at 22:37
  • What is AuthorAttribute here? Is it a class that is derived from Attribute? @Adam Markowitz – Sarath Subramanian Dec 06 '14 at 07:32
  • 1
    Yes. The OP is using a custom attribute named 'Author'. See here for an example: http://msdn.microsoft.com/en-us/library/sw480ze8.aspx – Adam Markowitz Dec 06 '14 at 21:03
  • 1
    The performance cost of casting the attribute is utterly insignificant compared to every other operation involved (except the null check and string assignments). – SilentSin Nov 21 '17 at 05:26
145

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.

T.Todua
  • 53,146
  • 19
  • 236
  • 237
Mo Valipour
  • 13,286
  • 12
  • 61
  • 87
92

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;
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
maxspan
  • 13,326
  • 15
  • 75
  • 104
41

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"
Mikael Engver
  • 4,634
  • 4
  • 46
  • 53
  • 1
    How can i get description attribute from const `Fields`? – Amir Nov 02 '15 at 19:44
  • 1
    You will get a: Error 1775 Member 'Namespace.FieldName ' cannot be accessed with an instance reference; qualify it with a type name instead. If you need to do this, I suggest to change 'const' to 'readonly'. – Mikael Engver Nov 03 '15 at 09:47
  • 1
    You should have a lot more useful vote than that, honestly. It's a very nice and useful answer to many cases. – David Létourneau Jan 14 '16 at 16:26
  • 1
    Thanks @DavidLétourneau! One can only hope. Seems as if you helped a little bit in that. – Mikael Engver Jan 14 '16 at 19:39
  • :) Do you think it's possible to have the value of all attributes for one class by using your generic method and assign the value of the attribute to each properties ? – David Létourneau Jan 15 '16 at 18:51
  • @DavidLétourneau : I think you could, but I if you are in a modern environment and can use C# 6.0 I would use Auto-Property Initializers instead. See an example here: https://dotnetfiddle.net/N58x7J . – Mikael Engver Jan 19 '16 at 09:21
22

You can use GetCustomAttributesData() and GetCustomAttributes():

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);
BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
13

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; }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
10
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);
Daniel Dušek
  • 13,683
  • 5
  • 36
  • 51
3
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();
Victor
  • 46
  • 3
3

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.

Mirko Brandt
  • 121
  • 2
2

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.

Carter Medlin
  • 11,857
  • 5
  • 62
  • 68
2

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

WtFudgE
  • 5,080
  • 7
  • 47
  • 59
1

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 );
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
1

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;
}
Asaf
  • 477
  • 6
  • 6
0
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.

nicecatch
  • 1,687
  • 2
  • 21
  • 38
petrosmm
  • 528
  • 9
  • 23
0

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);
Mohamed.Abdo
  • 2,054
  • 1
  • 19
  • 12
0

If you want get property having the custom Attribute then please try the following:

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

PropertyInfo p = propertyInfos.Where(x => x.GetCustomAttribute() != null);