Closed sjoerd222888 closed 8 years ago
That's going to be a bit more complicated than that :)
Here's what's needed to make your test work:
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
IList<Instruction> instructions = myAction.Method.GetInstructions();
DynamicMethod dynamicCallback = new DynamicMethod("myAction", typeof(void), new Type[] { typeof(string) }, true);
ILGenerator il = dynamicCallback.GetILGenerator();
foreach (Instruction instruction in instructions)
{
switch (instruction.OpCode.OperandType)
{
case OperandType.InlineNone:
if (instruction.OpCode == OpCodes.Ldarg_1)
il.Emit(OpCodes.Ldarg_0);
else
il.Emit(instruction.OpCode);
break;
case OperandType.InlineMethod:
il.Emit(instruction.OpCode, (MethodInfo)instruction.Operand);
break;
case OperandType.InlineString:
il.Emit(instruction.OpCode, (string)instruction.Operand);
break;
default:
throw new NotImplementedException();
}
}
dynamicCallback.Invoke(null, new object[] { "World" });
You can't blindly take instructions from a method and copy them into DynamicMethod
.
The first thing to note here is that some instructions have operands. Your method body looks like:
nop
ldstr "Hello"
ldarg.1
call System.String::Concat(System.String,System.String)
call System.Console::WriteLine(System.String)
nop
ret
I've only implemented what's needed to work here. ldstr takes a literal string, call takes a MethodInfo. There's a bunch of other instructions that take operands that you'll need to implement.
The second thing is that in:
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
The lambda is compiled into a class, and the code of the lambda is compiled into an instance method, whereas DynamicMethods are static methods by definition. It means that you need to adjust the index of the arguments, as instance methods have the this
argument at index 0.
The exception you saw was because you emitted a ldarg.1
while there's no argument at index 1 in the DynamicMethod, the string argument will be at index 0.
Good luck!
Many thanks for the detailed explanation.
Maybe I completely misunderstand some basics, but I thought it would be possible to do the following:
But doing so will end up with a TargetInvocationException with the message: "Operation could destabilize the runtime.".
According to my understanding the il code generated with your extension library should be valid to be used to create a DynamicMethod, isn't it? So I suppose there is an issue with the generated IL code. Please forgive me when I wrong and I misunderstood some basics about IL generation.