Отражение свойства для получения атрибутов. Как быть, когда они определены в другом месте?

У меня есть класс Bar, как это:

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; } } 
}

Мне нужно найти атрибут [Range(0,255)], отражающий ТОЛЬКО свойство Bar.FooProp. Я имею в виду, что реквизит оформлен в экземпляре класса (.. new Foo()), а не в классе, когда я сейчас разбираю. Infact Bar.FooProp не имеет атрибутов

РЕДАКТИРОВАТЬ

Я переместил атрибуты в определение интерфейса, поэтому мне нужно проанализировать унаследованные интерфейсы, чтобы найти их. Я могу это сделать, потому что класс Bar должен реализовывать IFoo. В этом конкретном случае мне повезло, но проблема остается, когда у меня нет интерфейсов... Я приму к сведению в следующий раз

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));
        }
      }
    }
  }

person Marco Mangia    schedule 20.06.2009    source источник


Ответы (2)


У меня была аналогичная ситуация некоторое время назад, когда у меня был атрибут, объявленный для метода в интерфейсе, и я хотел получить атрибут из метода для типа, реализующего интерфейс. Например:

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

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

Приведенный ниже код используется для проверки всего интерфейса, реализованного типом, для просмотра того, какие члены интерфейса реализует данный method (с использованием GetInterfaceMap), и для возврата любых атрибутов этих членов. Прямо перед этим я также проверяю, присутствует ли атрибут в самом методе.

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 )
  );
}
person Emperor XLII    schedule 19.10.2009

При взгляде на FooProp нет ничего, что указывало бы на существование Foo (в любой точке). Возможно, вы могли бы добавить атрибут для идентификации поля foo и подумать об этом (через FieldInfo.FieldType)?

person Marc Gravell    schedule 20.06.2009
comment
на самом деле, ключ отражается внутри метода get/set. Я не знаю, есть ли способ понять, что возвращаемый параметр является вызовом метода экземпляра. - person Marco Mangia; 20.06.2009
comment
Если вы внутри get/set, то вы уже знаете тип... просто используйте известный тип...? - person Marc Gravell; 20.06.2009
comment
mhh... Я думал переместить атрибуты определения интерфейса. Поэтому я размышляю непосредственно о атрибутах, унаследованных интерфейсом, а не о реализованных свойствах. Может быть, Марк? - person Marco Mangia; 20.06.2009
comment
На интерфейсе будет работать - но становится немного сложно решить, когда метод/свойство реализует интерфейс, так как есть проблемы с явной реализацией, дженериками и т. д. - это не тривиально, но может быть сделано. - person Marc Gravell; 20.06.2009
comment
Привет, Марк, как только что было объяснено (см. редактирование), определение интерфейса богаче, чем раньше. Это работает, но я не очень за будущее. Я имею в виду, что теперь основная цель состоит в том, чтобы собрать все атрибуты, разбросанные вокруг, в единственный ОДИН buddy частичный класс Bar. По двум причинам: платформа проверки xVal нуждается в этом, и все подсказки пользовательского интерфейса могут привести к созданию моих представлений (текстовые поля, области редактирования и т. д.) - person Marco Mangia; 21.06.2009