Reputation: 179
Using Ildasm I got this:
.method public hidebysig virtual instance string
Mymethod() cil managed
{
// Code size: 12 (0xc)
.maxstack 1
.locals init ([0] string CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld string Lab11_type_.SomeType::some_text
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of method MyType::Mymethod
Than I tried to do it by myself like this :
var my_field = type.DefineField("field1", typeof(System.String), FieldAttributes.Public);
var method2 = type.DefineMethod("MyTry", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot, typeof(string),null);
ILGenerator myMethodIL2 = method2.GetILGenerator();
myMethodIL2.Emit(OpCodes.Nop);
myMethodIL2.Emit(OpCodes.Ldarg_0);
myMethodIL2.Emit(OpCodes.Stfld, my_field);
myMethodIL2.Emit(OpCodes.Stloc_0);
myMethodIL2.Emit(OpCodes.Br_S);
myMethodIL2.Emit(OpCodes.Ldloc_0);
myMethodIL2.Emit(OpCodes.Ret);
And whe I tried to Invoke my method got an error. Is there are somthing wrong with my code ?
Upvotes: 1
Views: 367
Reputation: 40838
First the method you are trying to duplicate is reading a field and returning the value:
public virtual string MyMethod()
{
return field1;
}
This is simple enough, however you have decompiled a debug version which contains all sorts of unnecessary information for making the debugging experience richer. This is unnecessary for dynamically generated code. A release build has very concise IL:
.method public hidebysig newslot virtual
instance string MyMethod () cil managed
{
// Method begins at RVA 0x2050
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld string C::'field1'
IL_0006: ret
}
That should be easy enough to figure out, so I'll leave it as an exercise. In general I find that optimized (i.e. "Release") IL is easier to read.
As for your code, you've got three issues:
Fixing all of these gives:
ILGenerator myMethodIL2 = method2.GetILGenerator();
myMethodIL2.DeclareLocal(typeof(string));
var label = myMethodIL2.DefineLabel();
myMethodIL2.Emit(OpCodes.Nop);
myMethodIL2.Emit(OpCodes.Ldarg_0);
myMethodIL2.Emit(OpCodes.Ldfld, my_field);
myMethodIL2.Emit(OpCodes.Stloc_0);
myMethodIL2.Emit(OpCodes.Br_S, label);
myMethodIL2.MarkLabel(label);
myMethodIL2.Emit(OpCodes.Ldloc_0);
myMethodIL2.Emit(OpCodes.Ret);
Note that it doesn't matter where you call DefineLabel or DefineLocal so much. But MarkLabel must come at the correct position because you are trying to jump to an instruction at a specific offset.
Upvotes: 3