2011-03-10 6 views
5

Per la prima volta in assoluto ho effettivamente dovuto eseguire manualmente la scansione dell'assieme. Mi sono imbattuto in C# - how enumerate all classes with custom class attribute? che mi ha impostato conBest practice per eseguire la scansione di tutte le classi e metodi per l'attributo personalizzato

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

che era abbastanza semplice per espandere verso il livello di metodo

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

Dovrei provare a combinare queste 2 per fare questo in una singola scansione, o è che sta cadendo nell'ottimizzazione iniziale? (la scansione verrà eseguita solo all'avvio dell'app)

C'è qualcosa di diverso che sarebbe più ottimale fare per la scansione dei metodi poiché ci sono molti più metodi dei tipi negli assiemi?

+0

Io vado a scommettere che l'enumerazione dei gruppi e dei tipi sta per essere molto più veloce di trovare e istanziare i tuoi attributi, in modo tale che il caching delle assemblee e tipi è sarà inutile – Gabe

risposta

3

riflessione è molto lento ...

io pensi ho andare le nozioni di base lì. Ti consiglio di cambiare leggermente il codice per evitare di eseguire la scansione completa.

Se devi farlo più di una volta, ti consiglio anche di prendere in considerazione la memorizzazione nella cache dei risultati per qualsiasi periodo di tempo sia appropriato.

sorta come questo pseudo-codice:

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

Penso che si possa ottimizzare questo, ma dipende da come gli attributi sono posizionati su metodi e tipi. Se si sa che tutti i tipi e/oi metodi con attributo speciale sono definiti in particolari gruppi, è possibile eseguire la scansione solo di questi assiemi.

Inoltre si potrebbe definire alcuni metodi, come:

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

e utilizzare questi metodi nel metodo di scansione principale.

Così il vostro metodo di scansione risultato potrebbe apparire come:

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