views:

40

answers:

2

I am given:

  • A class "T" which implements properties that are decorated with Attributes that I am interested in.

  • A PropertyInfo "p" representing a property belonging to (1) an interface "I" that T implements, (2) a base class "B" that T inherits from, or (3) the class T itself.

I need to get the Attributes defined on (or inherited by) the properties in T, even if p's DeclaringType is an interface that T implements or a class that T inherits from. So I need a way to get from p to the PropertyInfo that actually exists on T. Thus it seems that there are 3 cases:

  1. p.DeclaringType == typeof(T)

    This is the trivial case. I can iterate through T's properties until I find the match. Example:

    return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                    .FirstOrDefault(property => property == p)
    
  2. p.DeclaringType == typeof(I) where I is an interface that T implements

    This is more complicated. I found that I can use an InterfaceMapping to find the corresponding implementation of the p in T. It seems kind of hackish, but here what works:

    if (p.DeclaringType.IsInterface &&
        typeof(T).GetInterfaces().Contains(p.DeclaringType))
    {
        InterfaceMapping map = typeof(T).GetInterfaceMap(p.DeclaringType);
        MethodInfo getMethod = p.GetGetMethod();
        for (int i = 0; i < map.InterfaceMethods.Length; i++)
        {
            if (map.InterfaceMethods[i] == getMethod)
            {
                MethodInfo target = map.TargetMethods[i];
                return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                .FirstOrDefault(property => property.GetGetMethod() == target);
            }
        }
    }
    
  3. p.DeclaringType == typeof(B) where B is a class that T inherits from

    I have not yet been able to figure out how to identify the property on T that overrides a virtual property p defined in Ts base class B.

So my questions are

  • In case 3 how do I find the PropertyInfo on T that overrides the property p on B?
  • Is there a better way to do all three? Perhaps a way to unify the three cases.
+1  A: 

I think you're missing a case : it is possible that T just inherits the property from B, without overriding it (unless you know for sure this won't happen in your specific scenario).

Anyway, you just need to search the property by name, using typeof(T).GetProperty, since there can't be 2 properties with the same name in a given class (unlike methods, which can have several overloads). However, you need to watch out for the case where T hides the property inherited from B, using the new modifier. To handle that case, you can check the Attributes of the property's getter method (obtained with GetGetMethod) : if the NewSlot flag is present, it hides the inherited getter.

Thomas Levesque
When implementing interfaces explicitly, properties can have the same name.
Greg
Also, you are quite correct that I am missing a case.
Greg
A: 

I found a way to answer case 3. The key is MethodInfo.GetBaseDefinition

if (typeof(T).IsSubclassOf(p.DeclaringType))
{
    MethodInfo baseDefinition = p.GetGetMethod().GetBaseDefinition();
    return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                    .FirstOrDefault(property => property.GetGetMethod().GetBaseDefinition() == baseDefinition);
}

However this only works for properties that have been overridden on T.

Edit:

By comparing the following, it doesn't matter if the properties have or haven't been overriden on T:

property.GetGetMethod().GetBaseDefinition().MetadataToken == baseDefinition.MetadataToken
Greg