Pergunta baseada no exemplo do MSDN .
Digamos que tenhamos algumas classes de C # com HelpAttribute no aplicativo de desktop independente. É possível enumerar todas as classes com esse atributo? Faz sentido reconhecer classes dessa maneira? O atributo personalizado seria usado para listar as opções de menu possíveis, a seleção do item trará para a instância de tela dessa classe. O número de classes / itens aumentará lentamente, mas dessa forma podemos evitar enumerá-los em outros lugares, eu acho.
c#
class
attributes
custom-attributes
enumerate
tomash
fonte
fonte
Select
método de extensão, e o compilador gerará uma máquina de estado como faria se você ligasseSelect
por causa do uso deyield return
. Finalmente, quaisquer ganhos de desempenho que possam ser obtidos na maioria dos casos são micro-otimizações.Bem, você teria que enumerar todas as classes em todos os assemblies carregados no domínio do aplicativo atual. Para fazer isso, você chamaria o
GetAssemblies
método naAppDomain
instância para o domínio de aplicativo atual.A partir daí, você chamaria
GetExportedTypes
(se quiser apenas tipos públicos) ouGetTypes
em cada umAssembly
para obter os tipos que estão contidos na montagem.Em seguida, você chamaria o
GetCustomAttributes
método de extensão em cadaType
instância, passando o tipo do atributo que deseja encontrar.Você pode usar o LINQ para simplificar isso para você:
A consulta acima fornecerá a você cada tipo com seu atributo aplicado a ela, juntamente com a instância do (s) atributo (s) atribuído (s) a ela.
Observe que, se você tiver um grande número de assemblies carregados no domínio do aplicativo, essa operação poderá ser cara. Você pode usar o LINQ paralelo para reduzir o tempo da operação, assim:
Filtrando-o em um específico
Assembly
é simples:E se a montagem tiver um grande número de tipos, você poderá usar o Parallel LINQ novamente:
fonte
Outras respostas referenciam GetCustomAttributes . Adicionando este como um exemplo do uso de IsDefined
fonte
Como já foi dito, a reflexão é o caminho a percorrer. Se você vai chamar isso com frequência, sugiro que os resultados sejam armazenados em cache, pois a reflexão, especialmente enumerando todas as classes, pode ser bastante lenta.
Este é um trecho do meu código que percorre todos os tipos em todos os assemblies carregados:
fonte
Este é um aprimoramento de desempenho sobre a solução aceita. A iteração, embora todas as classes possam ser lentas, porque existem muitas. Às vezes, você pode filtrar uma montagem inteira sem observar nenhum de seus tipos.
Por exemplo, se você estiver procurando por um atributo que você mesmo declarou, não espera que nenhuma das DLLs do sistema contenha nenhum tipo com esse atributo. A propriedade Assembly.GlobalAssemblyCache é uma maneira rápida de verificar as DLLs do sistema. Quando tentei isso em um programa real, descobri que podia pular 30.101 tipos e só tenho que verificar 1.983 tipos.
Outra maneira de filtrar é usar Assembly.ReferencedAssemblies. Presumivelmente, se você deseja classes com um atributo específico, e esse atributo é definido em uma montagem específica, você só se preocupa com essa montagem e outras montagens que a referenciam. Nos meus testes, isso ajudou um pouco mais do que a verificação da propriedade GlobalAssemblyCache.
Combinei os dois e consegui ainda mais rápido. O código abaixo inclui os dois filtros.
fonte
No caso de limitações Portable .NET , o seguinte código deve funcionar:
ou para um grande número de montagens usando o loop-state
yield return
:fonte
Podemos melhorar a resposta de Andrew e converter tudo em uma consulta LINQ.
fonte