Jun 16, 2016

Realizando consultas em assemblys .NET

Desde 2008 venho não apenas desenvolvendo soluções em NET como também  tenho dedicado um tempo considerável manipulando assemblys .NET o que, invariavelmente, me leva a frequentemente ter que responder questões como:
  • Quantos tipos em um assembly específico são Value Types?
  • Quantos (e quais) tipos expões mais que x propriedades ?
  • Existe alguma interface / classe que não segue alguma convenção de nomenclatura?etc.
Para responder estas questões eu basicamente usava duas possíveis estratégias: i) escrevia um programa usando Mono.Cecil (ou .NET Reflection) e assim navegava nos metadados (métodos, tipos, etc) ou ii) recorria a mágica das regular expressions (o que sempre me garantia algumas horas de "diversão"). 

O problema com estas soluções não é que as mesmas não funcionem, mas sim que frequentemente eu acabava realizando manualmente, tarefas tecnicamente passiveis de ser automatizadas.

Mas esta situação estava destinada a mudar desde minha última viagem para um evento interno na empresa em que trabalho. Neste evento eu participei em um projeto onde alguns amigos usaram o LINQPad para visualizar o MS IL gerado para um código C# específico. Normalmente eu usaria o ILSpy para isto mas, novamente, para tanto eu teria que escrever um programa e compilar o mesmo para, só depois, abrir o assembly no ILSpy o que me fez olhar com mais atenção para o LINQPad e, finalmente, cair a ficha: eu poderia usar o LINQPad não apenas para visualizar o IL gerado rapidamente; mais importante que isso, eu poderia usar o mesmo para automatizar minhas "pesquisas" em assemblys .NET! (nossa, descobri a pólvora :)

Assim que retomei minhas tarefas diárias eu comecei a testar a ideia de fazer consultas sobre .NET assemblys e o resultado me deixou bem satisfeito. Sinceramente, a ideia é tão simples que eu não entendo porque levou tanto tempo para eu pensar nisso :(. O exemplo abaixo demonstra o uso da técnica:

var a = Assembly.LoadFrom(@"S:\Unity\Editor\Data\Managed\UnityEngine.dll");
var result = from t in a.GetTypes()
             where Char.IsLower(t.Name[0])
             select t.FullName;

result.Dump();

Não consigo imaginar uma forma muito mais simples para você obter uma lista de tipos em um assembly cujo nome comece com uma letra minúscula! (tente fazer isso usando regular expressions nos fontes de um projeto :) O melhor é que este trecho de código é uma consulta LINQ padrão sobre metadados .NET, ou seja, nada de novo :)

Apesar de não haver quase nada específico (apenas o método Dump()) ao LINQPad na consulta acima, o uso deste aplicativo torna o processo muito mais simples e natural: nada de escrever um programa para rodar este trecho de código; nada de compilar, etc.

Se você deseja experimentar também, basta copiar/colar a consulta acima no LINQPad, modificar o path do assembly para um que faça sentido para você e executar a mesma pressionando F5:




Simples assim! É claro que para utilizar esta técnica eficientemente você deve ter um bom conhecimento sobre .NET Reflection mas isto não deve ser problema.

No próximo post eu descreverei como tornar estas consultas ainda mais flexíveis através da introdução de um custom driver para o LINQPad!

Have fun!

Read this post in English.

No comments: