I got the feeling that C# programmers kind of fear of using Mono.Cecil.I think it’s just because they are didn’t try it. Cecil is a powerful tool for rewriting an assembly. And it does it in pretty simple way.
You can use Cecil for various tasks. One of the main usage is, AOP libraries. In general it can replace Reflection.Emit and sometimes ExpressionTrees. Those are also a very powerful tools, but I prefer Cecil.
So what is Cecil?
Cecil is a library written by Jb Evain to generate and inspect programs and libraries in the ECMA CIL format. It has full support for generics, and support some debugging symbol format.
In simple English, with Cecil, you can load existing managed assemblies, browse all the contained types, modify them on the fly and save back to the disk the modified assembly. (The quote taken from mono project website)
As I wrote, it can be Reflection.Emit alternative, but it has two important additional capabilities.
- Cecil has support for extracting the CIL bytecodes.
- Cecil does not need to load the assembly or have compatible assemblies to introspect the images.
Also at Cecil, in contrast to Emit, there is a difference between
You can think of cases where it’s important. I’ll show you these cases in a later post.
Cecil type system
The most important types you need to know to know, is the following:
MainModule property in the
AssemblyDefinition), used to read\write assembly\module. From this you start to work with Cecil.
MemberReference and his inherited children, is the metadata representation of type, method etc.
MethodBody and specially his
ILProccesor, is for rewrite an existing method, or write a new one.
Good to know: Cecil has library, called Cecil.Rocks that has a plenty extension methods that make your work even easier.
How Cecil do its magic?
To understand this, you need to know what is exist in your compiled managed assembly, specially the metadata section. I’m not going to deep into the subject now, only adding a small overview. (For more info I’m very recommending to read Simon Cooper post series, Anatomy of a .NET assembly)
All types, methods etc. saved in the assembly file in binary representation of 45 tables that has rows with the relevant information. To reference a row within a table, there is a something called
token. Token is a four bytes value that point to a row index in a specific table.
Example of existing tables:
- TypeDef – Store types in the same assembly
- TypeRef – Store types in a referenced assembly
- TypeSpec – Store instantiations of a generic type
Cecil is a Metadata Reader\Writer. It knows how to read metadata info and how to write it.
In the next post we will see how to write our first HellloWorld program with Cecil.