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:
System.Reflection.MemberInfo
public abstract object[] GetCustomAttributes(bool inherit);
public abstract object[] GetCustomAttributes(Type attributeType, bool inherit);
public abstract bool IsDefined(Type attributeType, bool inherit);
System.Attribute
public static Attribute[] GetCustomAttributes(MemberInfo member, bool inherit);
public static bool IsDefined(MemberInfo element, Type attributeType, bool inherit);
If you take the following simple class hierarchy:
public abstract class BaseClass
{
private bool result;
[DefaultValue(false)]
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.