views:

442

answers:

2

I have a class Bar like this:

class Foo : IFoo {
  [Range(0,255)]
  public int? FooProp {get; set}
}

class Bar : IFoo
{
  private Foo foo = new Foo();
  public int? FooProp { get { return foo.FooProp; }
                       set { foo.FooProp= value; } } 
}

I need to find the attribute [Range(0,255)] reflecting ONLY on the property Bar.FooProp. I mean, the prop is decorated in the class instance (.. new Foo()) not in the class when I am currently parsing. Infact Bar.FooProp has no attributes

EDIT

I moved attributes on the interface's definition, so what I have to do is parsing the inherited interfaces to find them. I can do that because Bar class must implement IFoo.In this particular case, I'm lucky, but the problem remains when I have no interfaces... I will take note for the next time

foreach(PropertyInfo property in properties)
{
  IList<Type> interfaces = property.ReflectedType.GetInterfaces();
  IList<CustomAttributeData> attrList;
  foreach(Type anInterface in interfaces)
  {
    IList<PropertyInfo> props = anInterface.GetProperties();
    foreach(PropertyInfo prop in props)
    {
      if(prop.Name.Equals(property.Name))
      { 
        attrList = CustomAttributeData.GetCustomAttributes(prop);
        attributes = new StringBuilder();
        foreach(CustomAttributeData attrData in attrList)
        {
            attributes.AppendFormat(ATTR_FORMAT,
                                        GetCustomAttributeFromType(prop));
        }
      }
    }
  }
+1  A: 

When looking at FooProp, there is nothing to identify the existence of a Foo (at any point). Perhaps you could add an attribute to identify the foo field, and reflect on that (via FieldInfo.FieldType)?

Marc Gravell
infact, the key is reflecting "inside" the get/set method. I dont know if there's a way to understand the return param is a call to an instance method..
Marco Mangia
If you are *inside* the get/set, then you already know the type... just use the known type...?
Marc Gravell
mhh...I was thinking to move the attributes the interface definition. So I reflect directly on inherited attribs by interface, not on the implemented properties. Could be right, Marc?
Marco Mangia
On the interface would work - but it gets a *little* tricky to resolve when a method / property implements an interface, as there are issues with explicit implementation, generics, etc - it isn't trivial, but can be done.
Marc Gravell
Hi Marc, as explained just now (see edit), the interface definition is richer than before. It works but I'm not very for the future. I mean, now the main goal is to collect all the attributes spreaded around into an only ONE *buddy* partial Bar class. For two reasons: xVal validation framework needs it and all the UI hints can drive codesmith to build my views (textboxes, edit areas, ecc)
Marco Mangia
A: 

I had a similar situation a while back where I had an attribute declared on a method in an interface, and I wanted to get the attribute from a method on a type implementing the interface. For example:

interface I {
  [MyAttribute]
  void Method( );
}

class C : I {
  void Method( ) { }
}

The code below is used to check all of the interface implemented by the type, see which interface members the given method implements (using GetInterfaceMap), and returns any attributes on those members. Right before this, I also check if the attribute is present on the method itself.

IEnumerable<MyAttribute> interfaceAttributes =
  from i in method.DeclaringType.GetInterfaces( )
  let map = method.DeclaringType.GetInterfaceMap( i )
  let index = GetMethodIndex( map.TargetMethods, method )
  where index >= 0
  let interfaceMethod = map.InterfaceMethods[index]
  from attribute in interfaceMethod.GetCustomAttributes<MyAttribute>( true )
  select attribute;

...

static int GetMethodIndex( MethodInfo[] targetMethods, MethodInfo method ) {
  return targetMethods.IndexOf( target =>
         target.Name == method.Name
      && target.DeclaringType == method.DeclaringType
      && target.ReturnType == method.ReturnType
      && target.GetParameters( ).SequenceEqual( method.GetParameters( ), PIC )
  );
}
Emperor XLII
mhhh interesting..
Marco Mangia