Retrieving Custom Attributes Using Reflection

  • 3 minutes to read
  • edit

The .NET Framework allows you to easily add metadata to your classes by using attributes. These attributes can be ones that the .NET Framework already provides, of which there are over 300, or you can create your own.

Using reflection, the ways to retrieve the custom attributes of a type are:

If you take the following simple class hierarchy:

public abstract class BaseClass
   private bool result;

   public virtual bool SimpleProperty
      get { return this.result; }
      set { this.result = value; }

public class DerivedClass : BaseClass
   public override bool SimpleProperty
      get { return true; }
      set { base.SimpleProperty = value; }

Given a PropertyInfo object (which is derived from MemberInfo, and represents a propery in reflection), you might expect that these methods would return the same result. Unfortunately, that isn’t the case.

The MemberInfo methods strictly reflect the metadata definitions, ignoring the inherit parameter and not searching the inheritance chain when used with a PropertyInfo, EventInfo, or ParameterInfo object. It also returns all custom attribute instances, including those that don’t inherit from System.Attribute.

The Attribute methods are closer to the implied behavior of the language (and probably closer to what you would naturally expect). They do respect the inherit parameter for PropertyInfo, EventInfo, and ParameterInfo objects and search the implied inheritance chain defined by the associated methods (in this case, the property accessors). These methods also only return custom attributes that inherit from System.Attribute.

This is a fairly subtle difference that can produce very unexpected results if you aren’t careful.

For example, to retrieve the custom  attributes defined on SimpleProperty, you could use code similar to this:

PropertyInfo info = typeof(DerivedClass).GetProperty("SimpleProperty");
var attributeList1 = info.GetCustomAttributes(typeof(DefaultValueAttribute), true));
var attributeList2 = Attribute.GetCustomAttributes(info, typeof(DefaultValueAttribute), true));

The attributeList1 array will be empty while the attributeList2 array will contain the attribute instance, as expected.