Reflection exclude all attributes from base class and specific attribute from all other derived classes

StackOverflow https://stackoverflow.com//questions/12667219

  •  11-12-2019
  •  | 
  •  

Question

I have the following base, middle and derived classes below::

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

I need a function that given a type, I need to return DataMemberAttribute attributes for all classes in the hierarchy except for the base.

In addition, all IgnoreForAllAttribute attributes should be ignored for all classes in the graph.

var derivedObject = new MostDerived();
var attributes = MyShinyAttributeFunction(derivedObject.GetType());
// returns [] { ValueMostDerived, ValueMiddle }
Était-ce utile?

La solution

Here's a LINQ sample that assumes DateMemberAttribute and IgnoreForAllAttribute are mutually exclusive

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

And a sample assuming the attributes are NOT mutually exclusive

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

Autres conseils

var properties = new List<PropertyInfo>();

GetProps(typeof(MostDerived), properties);

GetProps is a recursive function that gets the properties for the declaring type and then calls itself for the next type in the hierarchy. It stops when it gets to 'Base'

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

  }
}

The properties list will contain properties which have the DataMemberAttribute and don't have the IgnoreForAllAttribute.

You can use the following function to get desired results: In propertyNames, you will get the properties you need.

Usage:

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

Function:

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

You must make use of the following:

A recursive function that stops when BaseType does not exist should do the trick.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top