Jun 21, 2016

To infinity and beyond : more powerful .NET Metadata querying with LINQPad custom drivers and Mono.Cecil

In my last post I discussed how we can use LINQPad to query .NET metadata using .NET reflection. 

Even though that alone was already quite useful it has its own drawbacks:
  • No nice integration with LINQPad, requiring the user to load the assembly manually (even worse, forcing users to type the full assembly path)
  • No way to inspect / dump method bodies (so it is not possible, for instance, to find all methods that call into an specific method)
In order to overcome those limitations I decided to write a custom LINQPad driver for .NET assemblies (as we saw before this is not strictly necessary to use LINQ to explore .NET metadata, but it definitely can help to make the experience more pleasant/enabling some scenarios by, for instance, exposing some predefined Sources like all public typesmembers and the like).

You can read more about custom LINQPad drivers here, but in summary I created a static driver that exposes the following predefined query sources:
  • Types : A collection of all types (irrespective to accessibility and/or whether the type in question is a top level / inner type) from the assembly's main module.
  • PublicTypesA collection of all public types from the assembly's main module.
In addition to that I've also introduced some convenience functions that can be used in the queries:
  • AsString(method): An extension method for MethodBody that converts a method body into a formatted string with it's IL instructions.
  • Calls(method): An extension method for a MethodDefinition / MethodBody that takes a method (either as a MethodInfo or a MethodReference) and returns true if the method in question is being called in the method body.
  • References(type)An extension method for a MethodDefinition / MethodBody that takes a type (either as a string, a TypeInfo or a TypeReference) and returns true if the type in question is being referenced in the method body.
  • Property(name): An extension method (for TypeDefinition) that returns a property definition if the type has a matching one or null otherwise.
  • Event(name): An extension method (for TypeDefinition) that returns an event definition if the type has a matching one or null otherwise.
  • Field(name): An extension method (for TypeDefinition) that returns a field definition if the type has  a matching one or null otherwise.
You can have a glimpse of those features in the following screenshot:


If you are interested in using this, all you need to do is to download Cecil.LINQPad.Driver.lpx and install it in LINQPad by clicking Add connection "link" then "View more drivers...", then "Browse" and finally selecting Cecil.LINQPad.Driver.lpx file

Of course you can also grab the source code from GitHub and build it for yourself ;)

Feel free to comment, make suggestions, report issues, ask questions, etc.

Have fun!

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!

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.

Querying .NET assemblies with LINQPad

Since 2008 I have not only been playing / working with .NET on a daily basis; I've also done quite a lot of work with .NET assemblies and, as result, quite frequently I find myself trying to answer questions like:
  • How many types in the assembly are value types?
  • How many types exposes more than x properties?
  • Do we have any interfaces / types that does not conform to some specific naming convention?
  • etc.
In order to answer these questions I used to either write a quick program (with the help of Mono.Cecil) or ended up having some fun time with regular expressions (of course, running these regular expressions on the source code instead of the built assemblies). These solutions work relatively well but they have some serious drawbacks: i) lots of repetitive work, ii) it is harder to extract information from the source than from assemblies; iii) some times I don't have any source code at all, only the assembly, etc.

Since last Hackweek this was set to change! For some reason I can't explain (it is as if I have been in Mars for the last couple of years ;) I failed to even realize how powerful / flexible LINQPad has become; it is not the case that I was not aware about the tool itself; I knew LINQPad for some time (lets say, for 6 ~ 7 years) but I've never used it util last May; at that time a bunch of team mates were using it to quickly check generated IL for some C# code snippet and since I was participating in the same project I also needed to the same, so I decided to give it a try.

After returning to my daily tasks I sat one day and started experimenting with the idea of running queries on .NET assemblies for a couple of hours, and ended up really happy with the outcome. Actually, it was so easy that I have no idea why it took me so long to start using it: basically we can use .NET reflection and LINQ for Objects (as you can see in the following example):

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

or, in other words, show me all the types with a name starting with a lowercase char!

That is it, simple like that. The best part is that it is plain C# using LINQ and reflection to navigate through the .NET metadata.

Of course there's (almost) nothing specific to LINQPad in that code snippet; to me, the value that LINQPad aggregates lies on how easy and natural it looks like to use it to type such queries without the need to write / compile a separate application and the quick iteration times it enables.

If you want to try it also just copy / past that code to LINQPad, change the assembly path to one that makes sense to you and run (by pressing F5):




Once we have a way to easily run standard LINQ queries over assemblies we can unleash our imagination and rely on LINQPad power. But, before you get too excited, this approach does have one caveat though: you'll need to have a good grasp about .NET reflection to be able to use it effectively.

In my next post I'll write a custom LINQPad Driver in order to use Mono.Cecil instead of .NET Reflection making it even easier / more flexible to use!

Have fun!

Leia este post em Português.

Mar 11, 2016

Showing mercurial current branch in ConEmu prompt

As a long time git user, I had a relatively hard time when I started using mercurial CVS; one of the things that I really missed (this one goes to the list of annoyances) was the lack of support for showing the current branch in the console. In the following screenshot you can see that GIT console does show me the current branch (in the example, ofx)


Considering that I have a terrible memory and usually have at least 5 ~ 6 consoles open at any given time, it is not hard to conclude that, from time to time, I simply forget which is the current branch in each console. 

Since mercurial do not provide any help (other than keeping issuing hg branch command all the time ;), it happened, not once, but many times, that I found myself working in one console under the assumption that I was operating on branch Foo when in fact I was working in a completely different one.

Some days ago I had the idea of using mercurial hooks to detect when I am changing branches and setting the console prompt accordingly, but that did not worked out very well. To be fair, mercurial hooks worked as expected; the problem was that my hook was run by hg.exe process which itself is spawned from the console when one type, for instance, hg up -r Foo to change to branch Foo and this process (hg.exe) would need to change the PROMPT of its parent console, which is not allowed (at least AFAIK).

My next step was check whether ConEmu (it is not a secret that I'm in love with ConEmu ;))  had some support to achieve my goal and bingo! ConEmu support some extended ANSI codes, more specifically $E ] 9 ; 7 ; ”cmd“$E\  which allows one to execute the command specified in the string (cmd) and use its output as part of the PROMP string. 

With that information, I just created the following batch file:

@echo off
IF NOT EXIST .hg GOTO NOT_A_MERCURIAL_REPO
hg branch
GOTO END

:NOT_A_MERCURIAL_REPO
@echo !repo
:END

and set the PROMP to:

SET PROMPT=$E[32m$E]9;8;"USERNAME"$E\@$E]9;8;"COMPUTERNAME"$E\$S$E[1D$S$E[92m$P$E[90m$E[38;5;14m $Q$G $E]9;7;"path_to_above.bat"$E\$E[90m$G$E[m$S

and voalá!



In the picture above you can see that when the current directory is not a mercurial repository the string "!repo" is shown (I'll probably change that later and in this case will show nothing); also, as soon as I initialized a local repository the PROMPT changed to indicate that I was in the default branch. 

Now, the only missing bit was to configure ConEmu to automatically set that prompt when it creates a new console, which can be done by specifying a custom batch file (in my case I created a file named ConEmuInit.cmd):




Basically I copied the original file (that can be found in "%ConEmuBaseDir%\CmdInit.cmd") and change it accordingly.

Now I am happier ;) The changes of making mistakes are small now :)

Edit:
If you are using CONEMU  Build 160609 or newer you'll need to include you bath in a white list in order to CONEMU to run it:



Happy coding

Leia este post em Português!

Mostrando a branch corrente (mercurial) no prompt do ConEmu

Uma das funcionalidades que sempre gostei no GIT é o fato do GitBash (o console do mesmo) mostrar o nome da branch corrente (no exemplo abaixo, o a branch corrente é a ofx):


Não é de se admirar que quando comecei a usar o mercurial este recurso (ou melhor, a falta do mesmo) me causou certa dificuldade / desconforto.

Considerando que tenho uma memória muito ruim e que facilmente costumo ter entre 5 ~ 6 consoles abertos, é fácil entender a razão do porque, por mais de uma vez, eu estar trabalhando em um console assumindo que estava em uma branch qualquer quando na realidade estava em uma branch completamente diferente (não preciso dizer que isso me deu bastante dor de cabeça).

Alguns dias atras tive a ideia usar o conceito de hooks do mercurial para detectar quando eu mudasse de branch e assim setar o prompt com o nome da mesma; infelizmente esta ideia não funcionou muito bem pois hooks do mercurial são executados pelo processo hg.exe que por sua vez é executado a partir do console e assim sendo minhã solução não era viável pois um processo não pode mudar variáveis de ambiente (no caso o prompt) do processo parente, ou seja, o processo que o iniciou  (muito menos do processo parente do processo parente como neste caso).

Minha próxima tentativa foi verificar se o ConEmu (meu console preferido) tinha algum suporte que me permitisse definir o prompt dinamicamente; felizmente ConEmu suporta uma sintaxe estendida de códigos ANSI, mais precisamente $E ] 9 ; 7 ; ”cmd“$E\  o qual permite executar um programa (especificado pela string cmd) e usar a saída padrão do mesmo como parte do prompt

Munido destas informações eu simplesmente criei o aquivo bat abaixo:

@echo off
IF NOT EXIST .hg GOTO NOT_A_MERCURIAL_REPO
hg branch
GOTO END

:NOT_A_MERCURIAL_REPO
@echo !repo
:END

e defini a variável de ambiente PROMP como:

SET PROMPT=$E[32m$E]9;8;"USERNAME"$E\@$E]9;8;"COMPUTERNAME"$E\$S$E[1D$S$E[92m$P$E[90m$E[38;5;14m $Q$G $E]9;7;"caminho_do_arquivo_acima.bat"$E\$E[90m$G$E[m$S

e voalá!



Como você pode ver na imagem acima, quando o diretório corrente é um repositório mercurial a string => nome_da_branch_corrente é mostrada no prompt (caso o diretório corrente não seja um repositório mercurial a string !repo é apresentada). 

Como último passo configurei o ConEmu para definir o prompt toda vez que um novo console / tab é criado (para tanto eu simplesmente copiei o conteúdo do arquivo "%ConEmuBaseDir%\CmdInit.cmd" par um aquivo chamado ConEmuInit.cmd e o editei de forma que o memo defina o prompt com o valor desejado):



Agora sim, certamente minas dores de cabeça diminuirão :)

Edit:

Se você estiver usando a versão 160609 ou mais nova do CONEMU então será necessário configurar o mesmo para que o batch que você criou possa ser executado (no meu caso este batch encontra-se em c:\utils\hg_current_branch_or_die.bat)



Happy coding

Read this post in English!

Jan 21, 2016

Finding references to assemblies


The current task at my job requires me to patch (a fancy name for change) .NET assemblies, sometimes adding new members, sometimes changing type references, sometimes messing with the method implementation and sometimes doing a bit of all.

From time to time I need to find out why a assembly (A) has a reference to some other assembly (B); basically what I need to know is which type/member(s) from assembly B is being used by assembly A.

One particularly easy way (IMO) is to simply ildasm assembly A and look for references to B; in order to accomplish that you can do something like:


c:\temp> ildasm /all /out=c:\temp\assembly-a.il assembly-a.dll

After you generated the CIL from your assembly your next step is to search for the name of the assembly you want to find references for (in this example, Assembly_B); you'll find one or more (actually one for each referenced assembly) sessions in the IL code like:

.assembly extern /*23000005*/ Assembly_B
{

}

Now, you can either search for the name Assembly_B or by the number to its left (in this case 23000005)

.assembly extern /*23000005*/ Assembly_B
{
  .ver 1:0:0:0
}
.
.
.

IL_0006:  /* 28   | (0A)0000B2       */ call instance void [Assembly_B/*23000005*/]NamespaceName.TypeName::DoSomething()
.
.
.

In this example assembly A is using the instance method DoSomething() from type TypeName in namespace NamespaceName from assembly B.

What do you think?

Happy coding.

(Leia este post em português)