In my last post (http://blogs.msdn.com/weitao/archive/2009/05/28/override-properties-i.aspx) I revealed the truth behind property overriding. In today's article I will talk about how that impact the behavior of GetCustomAttributes.

In reflection a property is represented by a PropertyInfo object. There are two ways to get the custom attributes off of a PropertyInfo object:

  1. On System.Reflection.MemberInfo (which is the base class of PropertyInfo):
    • public abstract Object[] GetCustomAttributes(bool inherit)
    • public abstract bool IsDefined(Type attributeType, bool inherit)
  2. On System.Attribute:
    • public static Attribute[] GetCustomAttributes(MemberInfo member, bool inherit)
    • public static bool IsDefined(MemberInfo element,Type attributeType, bool inherit)

The inherit boolean value, according to MSDN, "Specifies whether to search this member's inheritance chain to find the attributes". However, from the previous post we've already learned that there is no real inheritance chain for properties. The property "inheritance" is actually defined by the inheritance of the getter/setter methods.

The two GetCustomAttributes APIs are actually designed for different purposes.

  1. MemberInfo.GetCustomAttributes strictly reflects the definitions in the metadata.
    • It ignores the "inherit" boolean value for PropertyInfo, EventInfo, and ParameterInfo and doesn't search the inheritance chain at all.
    • It returns all custom attribute instances, including the non-"CLS compliant" ones that don't inherit from System.Attribute.
  2. Attribute.GetCustomAttributes, on the other hand, is closer to the definition in the high level managed languages like C#.
    • It honors the "inherit" boolean value for PropertyInfo, EventInfo, and ParameterInfo. If "inherit" is true, it will search the "inheritance" chain defined by their associated methods.
      • For properties, these are their getters and setters.
      • For events, these are their adders and removers.
      • For parameters, these are their declaring methods.
    • According to CLS Rule 41: "Attributes shall be of type System.Attribute, or a type inheriting from it". Attribute.GetCustomAttributes only returns the custom attributes whose types inherit from System.Attribute.

So don't be surprised to find the two APIs return different results in the following code sample:

    [AttributeUsage(AttributeTargets.Property, Inherited = true)]

    public sealed class MyAttribute : Attribute { }

    public class Base

    {

        [MyAttribute]

        public virtual int MyProperty { get { return 0; } }

    }

    public class Derived : Base

    {

        public override int MyProperty { get { return 42; } }

    }

    class Program

    {

        static void Main()

        {

            PropertyInfo p = typeof(Derived).GetProperty("MyProperty");

            Console.WriteLine(p.IsDefined(typeof(MyAttribute), true));

            Console.WriteLine(Attribute.IsDefined(p, typeof(MyAttribute), true));

        }

    }