无法在C#中使用转换为IL的表达式调用静态方法

时间:2015-09-24 22:19:51

标签: c# expression-trees il

这是我第一次尝试从表达式生成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实例中执行调用,那么它可以正常工作。

不知道我哪里弄错了

1 个答案:

答案 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