I am writing a special-purpose mini-compiler and I often view disassembled CIL to figure out how to do things. But it's often not obvious how to translate the disassembled code to Reflection.Emit calls. Does a reference manual exist or any other source of information for doing this translation?
Edit: yes, mapping the opcodes to ILGenerator is pretty straightforward; I'm talking about all the other stuff like the .directives and attributes. For instance, how do you find out how to write the Reflection.Emit equivalent of something like Dictionary<TKey,TValue>
?
.class public auto ansi serializable beforefieldinit Dictionary<TKey, TValue>
extends System.Object
implements System.Collections.Generic.IDictionary`2<!TKey, !TValue>,
System.Collections.Generic.ICollection开发者_Go百科`1<valuetype
System.Collections.Generic.KeyValuePair`2<!TKey, !TValue>>,
...
{
.custom instance void System.Diagnostics.DebuggerDisplayAttribute::
.ctor(string) = { string('Count = {Count}') }
.method public hidebysig newslot virtual final instance bool TryGetValue
(!TKey key, [out] !TValue& 'value') cil managed
{
.maxstack 3
.locals init ([0] int32 num)
...
Or how about the "param" directive?
// public static void SayHello(string s = "Hello World!")
.method public hidebysig static void SayHello([opt] string s) cil managed
{
.param [1] = "Hello World!"
I would use the EmitHelper component of the BLToolkit for that purpose. It provides a fluent API resembling IL code, wrapping Reflection.Emit. Example extracted from the linked article:
EmitHelper emit = new AssemblyBuilderHelper("HelloWorld.dll")
.DefineType ("Hello", typeof(object), typeof(IHello))
.DefineMethod(typeof(IHello).GetMethod("SayHello"))
.Emitter;
emit
// string.Format("Hello, {0}!", toWhom)
//
.ldstr ("Hello, {0}!")
.ldarg_1
.call (typeof(string), "Format", typeof(string), typeof(object))
// Console.WriteLine("Hello, World!");
//
.call (typeof(Console), "WriteLine", typeof(string))
.ret();
Type type = emit.Method.Type.Create();
You are looking at the IL for the System.Collections.Generic.Dictionary<> class. The "Dictionary" class name is the string you pass to ModuleBuilder.DefineType().
The .param attribute is generated in C# version 4 or VB.NET for parameters that have a default value. You set it with the ParameterBuilder you get back from MethodBuilder.DefineParameter(). Use the SetConstant() method.
Since no one could answer the question, I conclude no documentation exists to show the relationship between ilasm syntax and Reflection.Emit calls.
As a side note, I've found that it's usually better to create code at run-time using RunSharp than Reflection.Emit. When I have time I'll try to figure out the new version of Cecil.
精彩评论