다음을 통해 공유


Hello World with DynamicILInfo

The following "Hello World" program shows how to use APIs in the class

DynamicILInfo. MSDN documentation will have more details on this class in
the next release.

using System;

using System.Reflection;

using System.Reflection.Emit;

 

class Demo {

  static void Main() {

    DynamicMethod dm =
new DynamicMethod("HelloWorld",
typeof(void), Type.EmptyTypes, typeof(Demo),
false);

    DynamicILInfo il = dm.GetDynamicILInfo();

 

    SignatureHelper sigHelper = SignatureHelper.GetLocalVarSigHelper();

    il.SetLocalSignature(sigHelper.GetSignature());

 

    byte[] code = { 0x00, 0x72,
0x01, 0x00, 0x00, 0x70, 0x28, 0x04, 0x00, 0x00, 0x0a,
0x00, 0x2a };

    int token0 = il.GetTokenFor("Hello world");

    int token1 = il.GetTokenFor(typeof(Console).GetMethod("WriteLine", new Type[] {
typeof(string) }).MethodHandle);

    PutInteger4(token0, 0x0002, code);

    PutInteger4(token1, 0x0007, code);

    il.SetCode(code, 8);

 

    dm.Invoke(null,
null);

  }

 

  static void PutInteger4(int
value, int startPos, byte[]
array) {

    array[startPos++] = (byte)value;

    array[startPos++] = (byte)(value
>> 8);

    array[startPos++] = (byte)(value
>> 16);

    array[startPos++] = (byte)(value
>> 24);

  }

}

> csc.exe demo.cs

> demo

Hello world

The DynamicILInfo class is different from
ILGenerator. It directly uses byte arrays to set IL code,
exception, and the local signature. So how can we get those byte arrays?

If the dynamic method we are going to create is based on a static method in some
existing assembly, we can view the IL code (bytes) of the static method via ildasm
or by using
MethodBody.GetILByteArray.
We can then build the byte array for SetCode from there. For all tokens used in
the original static method, be sure to replace them (bold, as shown above and below
in this example) with those generated from GetTokenFor. 

.method public hidebysig static void HelloWorld() cil managed

// SIG: 00 00 01

{

  // Method begins at RVA 0x2050

  // Code size 13 (0xd)

  .maxstack 8

  IL_0000: /* 00 |            
*/ nop

  IL_0001: /* 72 | (70)000001 */ ldstr "Hello world"

  IL_0006: /* 28 | (0A)000004 */ call void [mscorlib]System.Console::WriteLine(string)

  IL_000b: /* 00 |            
*/ nop

  IL_000c: /* 2A |            
*/ ret

}

To build the byte array for SetException, I'd suggest taking a couple of minutes
to read
ECMA spec partiton II (25.4.6) first. The Flags/TryOffset/TryLength/HandlerOffset/HandlerLength
... can be retrieved from MethodBody.ExceptionHandlingClauses
programatically. Be aware the exception type token (ClassToken) has to be obtained
from
GetTokenFor as well. Do you know Ildasm can show the raw exception information?
I did not know this until I learned about it recently from
Peli.:) Uncheck View->Expand try/catch and check show bytes; we will
see something like the following at the bottom of the method IL:

  // Exception count 1

  .try IL_002e to IL_0051 finally handler IL_0051 to IL_0065

  // HEX: 02 00 00 00 2E 00 00 00 23 00 00 00 51 00 00 00 14 00 00 00 00 00
00 00

}

Class
SignatureHelper offers a convenient way to construct the local variable
signature, if each local variable type is known. We can just make calls of SignatureHelper.AddArgument.

Are there any scenarios in your mind where using DynamicILInfo could be better than
using DynamicILGenerator? How'd you like to construct those byte arrays? I am thinking
about writing and sharing a tool, which, based on an existing method, generates
C# code to define the equivalent dynamic method (using DynamicILInfo) (if this turns
out to be a popular scenario).

Comments

  • Anonymous
    February 01, 2006
    Make it a Reflector language ;)
  • Anonymous
    February 07, 2006
    would be nice to see some sample code about ExceptionHandling...

    MethodBody contains a list of ExceptionHandleClausels, but how to get a byte-code of it and/or how to inject into a DynamicMethod
    specially using ILGenerator and/or DynamicILInfo...???

    but anyway, like your blogs... :)


  • Anonymous
    May 19, 2006
    I just would like to see an example of using DynamicILInfo for a method that is bound to an object. I have tried to do it and the runtime gives me an error "Bad Image Format xception was unhandled."
    The example in the help uses ILGenerator instead of DynamicILInfo. I have tried to find such an example on the internet and nothing has been found.
  • Anonymous
    June 09, 2006
    I think the DynamicILInfo class is bad for use. In your example I don't understand lines:

       array[startPos++] = (byte)(value >> 8);
       array[startPos++] = (byte)(value >> 16);
       array[startPos++] = (byte)(value >> 24);

    program work with:
       code[2] = token1;
       code[7] = token2;

    I'am using ILGenerator class:
       ILGenerator il = dm.GetILGenerator();
       il.Emit(OpCodes.nop);
       il.Emit(OpCodes.ldstr, "Hello, World!");
       il.Emit(OpCodes.call, typeof(System.Console).GetMethod("WriteLine"));
       il.Emit(OpCodes.ret);

    Please, say me about this lines:
       array[startPos++] = (byte)(value >> 8);
       array[startPos++] = (byte)(value >> 16);
       array[startPos++] = (byte)(value >> 24);

    And, excuise me, I'am russian and know English language very bad.  
  • Anonymous
    March 30, 2007
    Wow, thanks for this. There are no resources anywhere about this utility. I'm writing a class which uses Microsoft.CSharp to compile something then DynamicILInfo to program what I've compiled back into the current class. I didn't know about the tokenised calls though. Something tells me that finishing this is going to require a reasonably hefty pile of code and a lot more CIL metadata knowledge.