【问题标题】:Best practices to scan all classes and methods for custom attribute扫描自定义属性的所有类和方法的最佳实践
【发布时间】:2025-11-26 17:35:01
【问题描述】:

我第一次真正需要自己手动进行装配扫描。我遇到了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 项结合起来在一次扫描中执行此操作,还是只是属于早期优化? (扫描只会在应用启动时执行)

由于方法比程序集中的类型多得多,有什么不同的方法可以更好地扫描方法吗?

【问题讨论】:

  • 我敢打赌,枚举程序集和类型将比查找和实例化属性快得多,因此缓存程序集和类型将毫无意义。

标签: c# reflection performance


【解决方案1】:

反射很慢...

我认为您已经了解了基础知识。我建议您稍微更改代码以避免发生额外的完整扫描。

如果您必须多次执行此操作,我还建议您考虑在任何适当的时间段内缓存结果。

类似这样的伪代码:

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

【讨论】:

    【解决方案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>();
    }
    

    【讨论】:

      最近更新 更多