For the first time ever I've actually needed to do assembly scanning myself manually. I came across C# - how enumerate all classes with custom class attribute? which set me up with
var typesWithMyAttribute =
(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
let attributes = type.GetCustomAttributes(typeof(SomeAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = type, Attributes = attributes.Cast<SomeAttribute>() })
.ToList();
Which was simple enough to expand out to the method level
var methodsWithAttributes =
(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from method in type.GetMethods()
let attributes = method.GetCustomAttributes(typeof(SomeAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = type, Method = method,
Attributes = attributes.Cast<SomeAttribute>() })
.ToList();
Should I try to combine these 2 to do this in a single scan, or is that just falling into early optimization? (the scanning will only execute on app start)
Is there something different that would be more optimal to do for the scanning of the methods since there are far more methods than types in assemblies?
Reflection is very slow...
I think you've go the basics there. I'd recommend you change your code slightly to avoid the extra full scan taking place.
If you have to do this more than once, I'd also recommend you consider caching the results for whatever period of time is appropriate.
Sorta like this pseudo-code:
... (optional caches) ...
IDictionary<Type, IEnumerable<Attributes>> typeAttributeCache = new ...
IDictionary<MethodInfo, IEnumerable<Attributes>> methodAttributeCache = new ...
... (in another method or class) ...
foreach assembly in GetAssemblies()
foreach type in assembly.GetTypes()
typeAttributes = typeAttributeCache.TryGet(...) // you know the correct syntax, trying to be brief
if (typeAttributes is null)
typeAttributes = type.GetCustomAttributes().OfType<TypeImLookingFor>();
typeAttributeCache[type] = typeAttributes;
foreach methodInfo in type.GetMethods()
methodAttributes = methodAttributeCache.TryGet(...) // same as above
if (methodAttributes is null)
methodAttributes = methodInfo.GetCustomAttributes().OfType<TypeImLookingFor>();
methodAttributeCache[type] = methodAttributes;
// do what you need to do
I think you can optimize this but it depends on how the attributes are placed on methods and types. If you know that all of your types and/or methods with special attribute are defined in particular assemblies you can scan only these assemblies.
Also you could define some methods, like:
- IEnumerable<Type> GetAllTypesFromAssemblyByAttribute<TAttribute>(Assembly assembly) where TAttribute : Attribute
- IEnumerable<MethodInfo> GetAllMethodsFromTypeByAttribute<TAttribute>(Type type) where TAttribute : Attribute
and use these methods in your main scanning method.
So your result scan method could look like:
private void ScanAndDoSmth<TAttribute>(IEnumerable<Assembly> assemblies)
where TAttribute : Attribute
{
var result =
from assembly in assemblies
from type in GetAllTypesFromAssemblyByAttribute<TAttribute>(assembly)
let attributes = type.GetCustomAttributes(typeof(TAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = type, Attributes = attributes.Cast<TAttribute>();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With