Лучшие практики для сканирования всех классов и методов на предмет пользовательских атрибутов - PullRequest
5 голосов
/ 11 марта 2011

Впервые мне фактически понадобилось самостоятельно выполнять сканирование сборок.Я сталкивался с C # - как перечислить все классы с пользовательским атрибутом класса? , который настраивал меня на

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, чтобы сделать это в одном сканировании, или это просто относится к ранней оптимизации?(сканирование будет выполняться только при запуске приложения)

Есть ли что-то другое, что было бы более оптимальным для сканирования методов, поскольку методов в сборках гораздо больше, чем типов?

Ответы [ 2 ]

3 голосов
/ 11 марта 2011

Отражение очень медленное ...

Я думаю, что вы изучили основы. Я бы порекомендовал вам немного изменить код, чтобы избежать полного сканирования.

Если вам придется делать это более одного раза, я также рекомендую вам рассмотреть возможность кэширования результатов в течение любого подходящего периода времени.

Сорта, как этот псевдокод:

... (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 голосов
/ 11 марта 2011

Я думаю, вы можете оптимизировать это, но это зависит от того, как атрибуты размещены в методах и типах. Если вы знаете, что все ваши типы и / или методы со специальным атрибутом определены в определенных сборках, вы можете сканировать только эти сборки.

Также вы можете определить некоторые методы, такие как:

 - 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>();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...