2

I want to IL generate a dynamic method

delegate ArraySegment<byte> X(MyClass mc);

that calls a method of the signature on mc and returns its out parameter.

MethodInfo methInf = aClass.GetMethod("Y",
    BindingFlags.Public | BindingFlags.Instance, 
    null, new[] { typeof(ArraySegment<byte>).MakeByRefType() }, null);

but I don't know how to handle the out parameter. Here's the code I have so far.

DynamicMethod dm = new DynamicMethod("X", typeof(ArraySegment<byte>),
                                     new[] { typeof(MyClass) });
ILGenerator il = dm.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Callvirt, methInf, null);

What's needed to make the out param work?

Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
  • Just to clarify, your question is about how to emit a **call** to a method featuring an `out` parameter? –  Nov 12 '18 at 23:55
  • Since the parameter is already a ref type, you *should* just have to load the parameter (which *is* a reference) - whether that is arg0 or arg1 depends on instance vs static – Marc Gravell Nov 13 '18 at 00:05
  • `ref` and `out` are actually identical to the CLR. They only differ by how the compiler enforces that code sets an `out` before the method returns. – Crowcoder Nov 13 '18 at 00:39

1 Answers1

0

Thanks @MarcGravell (also for your deleted answer, which was of great help, as it spells out what you hint at in your comment to my question) and ILSpy, which helped me by compiling c# code to CIL, so I could just peek at that.

So here's the final, working code:

LocalBuilder local = il.DeclareLocal(typeof(ArraySegment<byte>));
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloca, local);
il.EmitCall(OpCodes.Callvirt, methInf, null);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldloc, local.LocalIndex);
il.Emit(OpCodes.Ret);

Invoking this is 10 times faster than doing methodInfo.Invoke(...) (on a methodInfo object that was created only once, of course).

Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156