When implementing IDataErrorInfo support on Windsor Silverlight Example that uses aspect-like features of Castle DynamicProxy, I came across something interesting. I think we all have written a code to fetch the properties of an object using Reflection API, but this one got me going for some time before I noticed what the problem is.

Suppose on our cliche Customer object we search for the members decorated with a specific attribute. Here’s the Customer class:

1
2
3
4
5
6
7
8
9
public class Customer
{
[Validation]
public virtual int Age { get; set; }

public virtual string Firstname { get; set; }

public virtual string Lastname { get; set; }
}

And the following test, you assume, would pass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[TestClass]
public class Playing_With_Reflection
{
[TestMethod]
public void Can_Fetch_Inherited_Attributes_On_Proxied_Object()
{
var customer = new ProxyGenerator().CreateClassProxy<Customer>();
var modelType = customer.GetType();

var property = modelType.GetProperties().Where(x => x.Name == "Age").First();
var attributes = property.GetCustomAttributes(typeof(ValidationAttribute), true);

Assert.IsNotNull(attributes);
Assert.IsTrue(attributes.Length == 1);
}
}

and (not?) to your surprise, the test fails!

The reason is while our Age property is in fact decorated with Validation attribute, the GetCustomAttribute on PropertyInfo returns an empty array. But why does it return an empty array? You may think this has something to do with the fact that DynamicProxy creates an look alike object on top of our Customer class? But we have specified that we need to get inherited attributes (passing “true” value on GetCustomAttributes above).

Well, here’s the news which should have been apparent: passing true to ICustomAttributeProvider.GetCustomAttributes method does NOT walk the type hierarchy.

The workaround, however, is pretty easy! Use Attribute class to do this and it will work just fine. The following test now passes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[TestClass]
public class Playing_With_Reflection
{
[TestMethod]
public void Can_Fetch_Inherited_Attributes_On_Proxied_Object()
{
var customer = new ProxyGenerator().CreateClassProxy<Customer>();
var modelType = customer.GetType();

var property = modelType.GetProperties().Where(x => x.Name == "Age").First();
var attributes = Attribute.GetCustomAttributes(property, typeof(ValidationAttribute), true);

Assert.IsNotNull(attributes);
Assert.IsTrue(attributes.Length == 1);
}
}