0

I'm trying to get all properties that has a custom attribute in the assembly. I did it this way but I'm doing it with two steps that does the same validation.

Ex:

abstract class XX

class Y1 : XX {
   [MyCustomAttribute(Value = "val A")]
   public int Something {get; set;}

}

class Y2 : XX {
   [MyCustomAttribute(Value = "val A")]
   public int Another {get; set;}

}

class Y3 : XX {
   [MyCustomAttribute(Value = "val B")]
   public int A1 {get; set;}

   [MyCustomAttribute(Value = "val C")]
   public int A2 {get; set;}

}

So the list with all property in the assembly that has it

Something
Another
A1
A2

I'm getting it with this linq

string attrFilter = "SomeValue";

var ts = this.GetType().Assembly.GetTypes().ToList().FindAll(c => typeof(XX).IsAssignableFrom(c) && !c.IsAbstract && !c.IsInterface);

var classes = from classe in ts
              where classe.GetProperties().ToList().FindAll(
                      property => property.GetCustomAttributes(typeof(MyCustomAttribute), false).ToList().FindAll(
                          att => typeof(MyCustomAttribute).IsAssignableFrom(att.GetType()) && (att as MyCustomAttribute).Value == attrFilter
                      ).Count > 0
                    ).Count > 0
              select classe;

this only give me the classes. So I need to extract the properties from each class

List<PropertyInfo> properties = new List<PropertyInfo>();
Parallel.ForEach(classes, classe => {
    var props = classe.GetProperties().ToList();
    var fks = from property in props
              where property.GetCustomAttributes(typeof(MyCustomAttribute), false).ToList().FindAll(
                          att => typeof(MyCustomAttribute).IsAssignableFrom(att.GetType()) && (att as MyCustomAttribute).Value == attrFilter
                      ).Count > 0
              select property;

    fks.ToList().ForEach(p => properties.Add(p));
});

As you can see, WHERE condition of the property linq is the same as the class query without the class list.

I was wondering if would be possible to extract the property from the first linq query

P. Waksman
  • 979
  • 7
  • 21
  • Use ts in your parallel.Foreach instead of classes? – Wearwolf Apr 04 '18 at 19:34
  • Yes it's possible but I've found it to be cleaner and easier to manage breaking the parts down into readable variables then query. Note that as long as you don't move the query from IEnumerable to List etc it won't run until it's needed; in other words, it'll operate as one big query anyways so there's no difference. However; if you're just trying to make it all one query just for kicks then go for it. – Michael Puckett II Apr 04 '18 at 19:42
  • I see, I was trying to get the property from the linq directly without that ForEach, but not sure if it will be possible. Yeh, if it turn into a little monster, will be bad :(. – P. Waksman Apr 04 '18 at 19:43

1 Answers1

3

Let's break it down.

Get all the types:

var types = System.AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany
    ( 
        a => a.GetTypes() 
    );

For all the types, get all the properties:

var properties = types.SelectMany
( 
    t => t.GetProperties() 
);

For all the properties, get those with the attribute you want:

var list = properties.Where
( 
    p => p.GetCustomAttributes(typeof(Attribute), true).Any() 
);

All together:

var list= System.AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany( a => a.GetTypes() )
    .SelectMany( t => t.GetProperties() )
    .Where
    ( 
        p => p.GetCustomAttributes(typeof(Attribute), true).Any() 
    );
John Wu
  • 50,556
  • 8
  • 44
  • 80