扫描自定义属性的所有类和方法的最佳实践

时间:2011-03-10 22:42:32

标签: c# reflection performance

我有史以来第一次真正需要手动进行装配扫描。我偶然发现了C# - how enumerate all classes with custom class attribute?,其中包含

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

这很简单,可以扩展到方法级别

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

我是否应该尝试将这两个结合起来在一次扫描中完成此操作,还是只是落入早期优化? (扫描只会在应用程序启动时执行)

是否有一些不同的方法可以更好地进行方法的扫描,因为方法中的方法远多于程序集中的类型?

2 个答案:

答案 0 :(得分:3)

反思很慢......

我认为你已经掌握了基础知识。我建议您稍微更改一下代码,以避免进行额外的全面扫描。

如果您不止一次这样做,我还建议您考虑在适当的任何时间段内缓存结果。

像这样的伪代码:

... (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

答案 1 :(得分:2)

我认为您可以对此进行优化,但这取决于属性在方法和类型上的放置方式。如果您知道在特定程序集中定义了具有特殊属性的所有类型和/或方法,则只能扫描这些程序集。

您还可以定义一些方法,例如:

 - IEnumerable<Type> GetAllTypesFromAssemblyByAttribute<TAttribute>(Assembly assembly) where TAttribute : Attribute
 - IEnumerable<MethodInfo> GetAllMethodsFromTypeByAttribute<TAttribute>(Type type) where TAttribute : Attribute

并在主扫描方法中使用这些方法。

因此,您的结果扫描方法可能如下所示:

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