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!

No comments: