Отражение исключает все атрибуты из базового класса и конкретный атрибут из всех других производных классов.

У меня есть следующие базовые, средние и производные классы ниже:

public class Base
{
    [DataMemberAttribute()]
    public int ValueBase { get; set; }

    [IgnoreForAllAttribute("Param1", "Param2")]
    public int IgnoreBase { get; set; }
}

public class Middle : Base
{
    [DataMemberAttribute()]
    public int ValueMiddle { get; set; }

    [IgnoreForAllAttribute("Param1", "Param2")]
    public int IgnoreMiddle { get; set; }
}

public class MostDerived : Middle
{
    [DataMemberAttribute()]
    public int ValueMostDerived { get; set; }

    [IgnoreForAllAttribute("Param1", "Param2")]
    public int IgnoreMostDerived { get; set; }
}

Мне нужна функция, которая по заданному типу возвращает атрибуты DataMemberAttribute для всех классов в иерархии, кроме базового.

Кроме того, все атрибуты IgnoreForAllAttribute следует игнорировать для всех классов в графе.

var derivedObject = new MostDerived();
var attributes = MyShinyAttributeFunction(derivedObject.GetType());
// returns [] { ValueMostDerived, ValueMiddle }

person morleyc    schedule 01.10.2012    source источник


Ответы (4)


Вот пример LINQ, в котором предполагается, что DateMemberAttribute и IgnoreForAllAttribute являются взаимоисключающими.

IEnumerable<PropertyInfo> MyProperties(object o)
{
   o.GetType().GetProperties()
    .Where(p => !(p.DeclaringType is Base))
    .Where(p => p.GetCustomAttributes(false).Any(a => a is DataMemberAttribute)
}

И образец, предполагающий, что атрибуты НЕ являются взаимоисключающими

IEnumerable<PropertyInfo> MyProperties(object o)
{
   o.GetType().GetProperties()
    .Where(p => !(p.DeclaringType is Base))
    .Where(p => 
       { 
          var attributes = p.GetCustomAttributes(false);
          return attributes.Any(a => a is DataMemberAttribute)
             && !attributes.Any(a => a is IgnoreForAllAttribute);
       }
}
person Richard Schneider    schedule 01.10.2012

var properties = new List<PropertyInfo>();

GetProps(typeof(MostDerived), properties);

GetProps — это рекурсивная функция, которая получает свойства объявляемого типа, а затем вызывает себя для следующего типа в иерархии. Он останавливается, когда доходит до «Базы».

private static void GetProps(Type T, List<PropertyInfo> Properties)
{
  if (T != typeof(Base))
  {
    var pis = T.GetProperties();

    foreach (var pi in pis)
    {
      if (pi.DeclaringType == T &&
        pi.GetCustomAttribute<DataMemberAttribute>() != null &&
        pi.GetCustomAttribute<IgnoreForAllAttribute>() == null)
      {
        Properties.Add(pi);
      }
    }

    GetProps(T.BaseType, Properties);

  }
}

Список свойств будет содержать свойства, которые имеют атрибут DataMemberAttribute и не имеют атрибута IgnoreForAllAttribute.

person wdavo    schedule 01.10.2012

Вы можете использовать следующую функцию для получения желаемых результатов: В propertyNames вы получите нужные вам свойства.

Использование:

List<string> propertyNames = new List<string>();
List<string> basePropertyNames = new List<string>();
MyShinyAttributeFunction(derivedObject.GetType(), ref propertyNames, ref basePropertyNames);

Функция:

void MyShinyAttributeFunction(Type type, ref List<string> propertyNames, ref List<string> basePropertyNames)
{
    if (type == null)
        return;

    MyShinyAttributeFunction(type.BaseType, ref propertyNames, ref basePropertyNames);

    foreach (var property in type.GetProperties())
    {
        foreach (object customAttr in property.GetCustomAttributes(false))
        {
            if (customAttr is DataMemberAttribute)
            {
                if (type.BaseType.Name.Equals("Object"))
                {
                    DataMemberAttribute attribute = (DataMemberAttribute)customAttr;
                    if (!basePropertyNames.Contains(property.Name))
                        basePropertyNames.Add(property.Name);
                }
                else
                {
                    DataMemberAttribute attribute = (DataMemberAttribute)customAttr;
                    if (!propertyNames.Contains(property.Name) && !basePropertyNames.Contains(property.Name))
                        propertyNames.Add(property.Name);
                }
            }
        }
    }
}
person Furqan Safdar    schedule 01.10.2012

Вы должны использовать следующее:

Рекурсивная функция, которая останавливается, когда BaseType не существует, должна помочь.

person Damian Schenkelman    schedule 01.10.2012