这是我第一次尝试从表达式生成IL,但我无法使其正常工作。我无法使用IL生成器调用静态方法。
我的班级结构是
B
我需要生成执行此操作的IL
public class TestClass
{
public static A Process(IServiceFactory factory, A a)
{
a.Value = 40;
return a;
}
}
public class A
{
public int Value { get; set; }
}
我设法生成的IL代码是
a.Value = 10;
TestClass.Process(factory,a)
注意:它从数组中加载实际的工厂对象。
此IL生成InvalidProgramException。但是,如果我可以将静态方法转换为实例方法并在TestClass实例中执行调用,那么它可以正常工作。
不知道我哪里弄错了
答案 0 :(得分:2)
看起来你在堆栈上加载了太多东西。第一部分似乎很好(忽略它与你想要的效果不符):
IL_0000: ldarg.1
IL_0001: castclass A
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: ldc.i4.0
IL_000a: ldelem.ref
IL_000b: castclass System.Func`1[System.Int32]
IL_0010: callvirt Int32 Invoke()/System.Func`1[System.Int32]
IL_0015: callvirt Void set_Value(Int32)/A
大致相当于以下C#:
A a = (A) arg1;
a.Value = ((Func<int>)arg0[0]).Invoke();
我不知道生成的方法是什么,因为你没有发布它们。无论如何,继续前进:
IL_001a: ldloc.0 // {a}
IL_001b: ldarg.0 // {a, arg0}
IL_001c: ldc.i4.1 // {a, arg0, 1}
IL_001d: ldelem.ref // {a, arg0[1]}
IL_001e: castclass IServiceFactory // {a, (IServiceFactory) arg0[1] }
IL_0023: ldarg.1 // {a, (IServiceFactory) arg0[1], arg1 }
IL_0024: castclass A // {a, (IServiceFactory) arg0[1], (A) arg1 }
IL_0029: call A Process(IServiceFactory, A)/TestClass // {a, TestClass.Process( (IServiceFactory) arg0[1], (A) arg1 ) }
IL_002e: ret
我在每条指令后用堆栈的状态注释了IL。您可以看到,当您到达返回指令时,堆栈上有两个值。似乎IL_001a上的ldloc.0
是错误的,不应该存在(此外,IL_0023-0024可以用简单的ldloc.0
替换而不是重新加载arg.1并将其转换为{ {1}})。这可以解释为什么当它不是静态方法时它才起作用:栈上的附加对象被视为调用方法的对象,因此它被正确使用。
根据您生成的方法是否应该返回值,您可能需要额外的A
来清除堆栈中pop
方法的返回值。既然你说它作为一个实例方法工作,这听起来像生成的方法返回一个值,所以你不需要TestClass.Process
。