Metaprogramming in .NET by Kevin Hazzard and Jason Bock
Looking back at the many years I spent as a programmer using Common Lisp, I now realise that one thing I loved about that language was the ability to easily do metaprogramming, It was a fairly trivial exercise to write code that generated other code, whether the need was an embedded domain specific language (implemented via macros) or the generation of a test suite from a grammar definition (for an SQL interpreter that I wrote to enable external parties to query our object model).
This book has a great discussion of what metaprogramming is, and describes how you might do it on the .NET platform.
Chapter one discusses the need for metaprogramming and this is followed by chapter two which looks at the relationship between metaprogramming and Reflection. Reflection only goes so far in this dimension – it certainly allows you to choose methods at runtime and even find methods that didn’t exist when your component was built. Reflection itself doesn’t allow you to add methods to existing classes or even define new classes and methods though so it is a little limited.
The rest of the book looks at the various other .NET technologies for generating classes and methods, starting with techniques for generating and then compiling source code. T4 templates, which you might use to define a data access layer and which are supported at compile time inside Visual Studio, and the CodeDom are studied in some detail.
The book moves on to Reflection.Emit for generating new assemblies, though this involves working at the IL level when defining new methods. This can be a little limiting, though it is also powerful as you have access to IL constructs that cannot be expressed in C#, such as fault handlers. Expression trees, originally added to support LINQ, offer an easier way for defining dynamic methods, using a tree structure of language agnostic object instances to express the desired functionality.
The System.Core assembly contains a compiler for such expression trees that you can access via the System.Linq.Expressions.LambdaExpression type with its Compile method which can build a delegate from an Expression tree.
The book also covers the alternative technologies of IL rewriting, using Cecil and PostSharp to produce and/or modify an existing assembly at the byte code level to add or augment classes and methods, and there is also information on the DLR, a technology associated with the implementation of the dynamic type in C#, which also acted as a compilation target for Ruby and Python when such languages were ported to the .NET platform. The final chapter covers Roslyn, the managed compiler which is currently available as a CTP. Roslyn supports compilation offering an open infrastructure that gives access to the parse trees, making it possible to easily write new refactorings inside Visual Studio, and also modify and recompile existing source code.
Metaprogramming has many practical uses and this book clearly shows how all this can be made to work on top of the .NET platform.