DynamicMethod 调用实例方法
DynamicMethod call Instance method
如果我从 class 方法内部创建 DynamicMethod,我如何从 DynamicMethod Delegate 调用我的 class 的另一个方法?我需要以某种方式在 DynamicMethod 代码中捕获 this 引用。
但是我找不到以对象作为参数的 ILGenerator.Emit 的重叠版本。
代码到此为止:
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);
}
我的问题是标有 ???
的行
How to reference the this
pointer from a DynamicMethod
?
在底层,方法没有特定的 this
指针,方法的第一个参数用作 this
.
要引用 this
指针,您需要执行以下操作:
- 在您的参数列表中添加一个新参数,匹配您要用作
this
的类型
- 随心所欲地使用该参数作为
this
- 使用
DynamicMethod.CreateDelegate(Type,Object)
创建委托以将第一个参数绑定到您的对象:return (D)(object)dm.CreateDelegate(dType, this);
请注意,创建动态方法的成本很高。如果为多个实例生成相同的 DynamicMethod,则应缓存方法本身,并使用缓存的方法创建委托,但使用不同的 target
参数。
如果我从 class 方法内部创建 DynamicMethod,我如何从 DynamicMethod Delegate 调用我的 class 的另一个方法?我需要以某种方式在 DynamicMethod 代码中捕获 this 引用。 但是我找不到以对象作为参数的 ILGenerator.Emit 的重叠版本。
代码到此为止:
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);
}
我的问题是标有 ???
的行How to reference the
this
pointer from aDynamicMethod
?
在底层,方法没有特定的 this
指针,方法的第一个参数用作 this
.
要引用 this
指针,您需要执行以下操作:
- 在您的参数列表中添加一个新参数,匹配您要用作
this
的类型
- 随心所欲地使用该参数作为
this
- 使用
DynamicMethod.CreateDelegate(Type,Object)
创建委托以将第一个参数绑定到您的对象:return (D)(object)dm.CreateDelegate(dType, this);
请注意,创建动态方法的成本很高。如果为多个实例生成相同的 DynamicMethod,则应缓存方法本身,并使用缓存的方法创建委托,但使用不同的 target
参数。