Jun 21, 2016

Para o infinito e além: consultas ainda mais poderosas sob metadados NET com drivers parta LINQPad e Mono.Cecil

No post anterior mostrei como usar o LINQPad para executar consultas em metadados .NET usando .NET Reflection, técnica que, apesar de muito útil, possui algumas limitações:
  • Zero integração com LINQPad, exigindo que o assembly seja carregado manualmente (ainda pior é fato de termos que digitar o caminho completo do assembly),
  • Como o .Net Reflection não expõe o corpo (instruções) de métodos, não é possível por exemplo, encontrar todos os métodos que executam algum outro método específico ou que acessem uma propriedade, etc.
Felizmente o LINQPad nos permite desenvolver / utilizar custom drivers que se integram muito mais naturalmente com o mesmo. No meu caso eu escrevi um que usa o Mono.Cecil (ao invés de .Net Reflection) para expor algumas fontes pré-definidas para consultas:
  • Types : Uma lista com todos os tipos (independentemente do tipo ser público ou não e/ou ser uma inner class) definidos no módulo principal do assembly.
  • PublicTypes: Uma lista composta por todos os tipos definidos publicamente.
Também introduzi as seguintes extensões (extension methods):
  • AsString(): Método que estende MethodBody retornando as instruções que compõe o corpo do método na forma de uma string.
  • Calls(method): Método que estende MethodDefinition / MethodBody retornando verdadeiro (true) caso o método passado como parâmetro seja executado pelo corpo do método estendido.
  • References(type)Método que estende MethodDefinition / MethodBody retornando verdadeiro (true) se o tipo passado como parâmetro for referenciado pelas instruções do corpo do método estendido.
  • Property(name): Método que estende TypeDefinition retornando a propriedade especificada pelo parâmetro (caso o tipo possua uma propriedade com o mesmo nome) ou null.
  • Event(name): Método que estende TypeDefinition retornando o evento que possua o nome igual ao passado como parâmetro ou null caso o tipo em questão não possua um evento com este nome.
  • Field(name): Método que estende TypeDefinition retornando o campo que possua o nome igual ao especificado no parâmetro ou null caso o tipo em questão não possua um campo com este nome.
Você pode ver um exemplo da utilização de tais métodos na imagem abaixo:


Para usar este Custom Driver você pode baixar o arquivo Cecil.LINQPad.Driver.lpx e instalar o mesmo no LINQPad clicando na opção Add connection,  depois em "View more drivers...", "Browse" e finalmente selecionando o arquivo que você acabou de baixar (Cecil.LINQPad.Driver.lpx)

É claro que você também pode baixar o source do mesmo do GitHub e compilar / instalar ;)


Uma vez instalado, o mesmo aparecerá na lista de opções de drivers disponíveis:



Pressione o botão Next e, a seguir selecione o assembly que você deseja fazer consultas. Lembre-se de, após abrir o assembly, clicar no dropdown "Connection" para selecionar a conexão que o LINQPad deve usar para rodar as consultas, ou seja, qual assembly deve ser usado como fonte nas consultas. No exemplo abaixo o assembly Boo.Lang.Parser.dll será usado:

Pronto. Agora você já pode rodar suas consultas LINQ!

Have fun!

No comments: