[quoted text, click to view] Fabio wrote:
> "Barry Kelly" <barry.j.kelly@gmail.com> ha scritto nel messaggio
> news:9oct13ln5hgipevammti8clevtvmhi8vki@4ax.com...
>
> >> I got a (traslated from italian) 'cannot find the method 'System.String
> >> System.Int32.ToString()'.
> >
> > Sounds like a bug in DbgCLR. I've never used it.
>
> No.
> I got the same error launching the compiled exe :(
Observe:
Step 1: Save the following as EmitWrite32.cs
---8<---
using System;
using System.Reflection;
using System.Reflection.Emit;
class Program
{
delegate void Method();
static void Main()
{
try
{
AssemblyBuilder assBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("Write42"),
AssemblyBuilderAccess.Save);
ModuleBuilder modBuilder =
assBuilder.DefineDynamicModule("Write42.exe");
TypeBuilder typeBuilder =
modBuilder.DefineType("App");
MethodBuilder mainMeth =
typeBuilder.DefineMethod("Main",
MethodAttributes.Public
| MethodAttributes.Static);
Write42(mainMeth.GetILGenerator());
typeBuilder.CreateType();
assBuilder.SetEntryPoint(mainMeth);
assBuilder.Save("Write42.exe");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static void Write42(ILGenerator cg)
{
LocalBuilder x = cg.DeclareLocal(typeof(Int32));
cg.Emit(OpCodes.Ldc_I4, 42);
cg.Emit(OpCodes.Stloc, x);
cg.Emit(OpCodes.Ldloca, x);
cg.Emit(OpCodes.Call,
typeof(System.Int32).GetMethod("ToString",
new Type[0]));
cg.Emit(OpCodes.Call,
typeof(System.Console).GetMethod("WriteLine",
new Type[] { typeof(string) }));
cg.Emit(OpCodes.Ret);
}
}
--->8---
Step 2: Compile with 'csc EmitWrite42.cs'
Step 3: Execute EmitWrite42.exe and observe that Write42.exe is created
without error.
Step 4: Execute Write42.exe and verify that it does indeed write 42,
without error.
Step 5: Execute 'ildasm Write42.exe -all -out:Write42.il', look inside
Write42.il and observe the following code has been emitted for App.Main:
---8<---
.method /*06000001*/ public static void
Main() cil managed
// SIG: 00 00 01
{
.entrypoint
// Method begins at RVA 0x2050
// Code size 19 (0x13)
.maxstack 1
.locals /*11000001*/ init (int32 V_0)
IL_0000: /* 20 | 2A000000 */ ldc.i4 0x2a
IL_0005: /* 0A | */ stloc.0
IL_0006: /* 12 | 00 */ ldloca.s V_0
IL_0008: /* 28 | (0A)000001 */ call instance string
[mscorlib/*23000001*/]System.Int32/*01000002*/::ToString() /* 0A000001
*/
IL_000d: /* 28 | (0A)000002 */ call void
[mscorlib/*23000001*/]System.Console/*01000003*/::WriteLine(string) /*
0A000002 */
IL_0012: /* 2A | */ ret
} // end of method App::Main
--->8---
In particular, I draw your attention to these two lines:
---8<---
IL_0008: /* 28 | (0A)000001 */ call instance string
[mscorlib/*23000001*/]System.Int32/*01000002*/::ToString() /* 0A000001
*/
IL_000d: /* 28 | (0A)000002 */ call void
[mscorlib/*23000001*/]System.Console/*01000003*/::WriteLine(string) /*
0A000002 */
--->8---
'call instance' in the first line, just 'call' in the second, all with
just a single opcode with value 0x28: magic!
Why?
Because the first call is to an instance method, and the second call is
to a static method. It really is as simple as that!
-- Barry
--