If I create a DynamicMethod from inside a class method how can I call another method of my class from the DynamicMethod Delegate? I need somehow to capture the this reference in the DynamicMethod code. But I can't find an overladed version of ILGenerator.Emit which takes an object as parameter.
The code is so far:
void CallOpc(string name, object[] inp, object[] outp)
{
//...
}
public D CreateDelegate<D>(string opcName) where D : class
{
var dType = typeof(D);
var invoke = dType.GetMethod("Invoke");
var parameters = invoke.GetParameters();
var paramTypes = parameters.Select(p => p.ParameterType).ToArray();
DynamicMethod dm = new DynamicMethod(
opcName,
invoke.ReturnType,
paramTypes,
true);
var inp = parameters.Where(p => !p.IsOut).Select(p => p.ParameterType).ToList();
var outp = parameters.Where(p => p.IsOut).Select(p => p.ParameterType).ToList();
if (invoke.ReturnType != typeof(void))
{
outp.Insert(0, invoke.ReturnType);
}
ILGenerator il = dm.GetILGenerator();
LocalBuilder invar = il.DeclareLocal(typeof(object[]));
LocalBuilder outvar = il.DeclareLocal(typeof(object[]));
il.Emit(OpCodes.Ldc_I4, inp.Count);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc, invar);
for (int i = 0; i < inp.Count; i++)
{
il.Emit(OpCodes.Ldloc, invar);
il.Emit(OpCodes.Ldc_I4, i);
int j = Array.IndexOf(paramTypes, inp[i]);
il.Emit(OpCodes.Ldarg, j);
if (!inp[i].IsClass)
{
il.Emit(OpCodes.Box, inp[i]);
}
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Ldc_I4, outp.Count);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc, outvar);
il.Emit(OpCodes.Ldarg_0); // <- push this on the evaluation stack ???
il.Emit(OpCodes.Ldstr, opcName);
il.Emit(OpCodes.Ldloc, invar);
il.Emit(OpCodes.Ldloc, outvar);
MethodInfo callOpcMeth = GetType().GetMethod("CallOpc", BindingFlags.Instance | BindingFlags.NonPublic);
il.Emit(OpCodes.Callvirt, callOpcMeth);
for (int o = 0; o < outp.Count; o++)
{
// TODO: handle out params and return value
}
il.Emit(OpCodes.Ret);
return (D)(object)dm.CreateDelegate(dType);
}
My problem is the line marked with ???
How to reference the
this
pointer from aDynamicMethod
?
At low level, methods do not have a specific this
pointer, instead the first argument of the method is used as this
.
To reference the this
pointer, here is what you have to do:
this
this
wherever you wantDynamicMethod.CreateDelegate(Type,Object)
to bind the first parameter to your object: return (D)(object)dm.CreateDelegate(dType, this);
Note that creating dynamic methods is expensive. If you generate the same DynamicMethod for multiple instances, you should cache the method itself, and create delegates using the cached method, but with different target
parameter.