Reflection - get attribute name and value on property

C#ReflectionPropertyinfo

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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

Solution 2 - C#

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.

Solution 3 - C#

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;

Solution 4 - C#

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"

Solution 5 - C#

You can use GetCustomAttributesData() and GetCustomAttributes():

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

Solution 6 - C#

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

Solution 7 - C#

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

Solution 8 - C#

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

Solution 9 - C#

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.

Solution 10 - C#

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.

Solution 11 - C#

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

Solution 12 - C#

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

Solution 13 - C#

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

Solution 14 - C#

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.

Solution 15 - C#

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

Solution 16 - C#

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser619891View Question on Stackoverflow
Solution 1 - C#Adam MarkowitzView Answer on Stackoverflow
Solution 2 - C#Mo ValipourView Answer on Stackoverflow
Solution 3 - C#maxspanView Answer on Stackoverflow
Solution 4 - C#Mikael EngverView Answer on Stackoverflow
Solution 5 - C#BrokenGlassView Answer on Stackoverflow
Solution 6 - C#Marc GravellView Answer on Stackoverflow
Solution 7 - C#Daniel DušekView Answer on Stackoverflow
Solution 8 - C#VictorView Answer on Stackoverflow
Solution 9 - C#Carter MedlinView Answer on Stackoverflow
Solution 10 - C#Mirko BrandtView Answer on Stackoverflow
Solution 11 - C#WtFudgEView Answer on Stackoverflow
Solution 12 - C#Stefan SteigerView Answer on Stackoverflow
Solution 13 - C#AsafView Answer on Stackoverflow
Solution 14 - C#petrosmmView Answer on Stackoverflow
Solution 15 - C#Mohamed.AbdoView Answer on Stackoverflow
Solution 16 - C#Rahul VaityView Answer on Stackoverflow