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

Cannot call static methods using expression converted to IL in C#

这是我第一次尝试从表达式生成 IL,但我无法让它工作。我无法使用 IL 生成器调用静态方法。

我的Class结构是

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 代码是

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
IL_001a: ldloc.0    
IL_001b: ldarg.0    
IL_001c: ldc.i4.1   
IL_001d: ldelem.ref 
IL_001e: castclass  IServiceFactory
IL_0023: ldarg.1    
IL_0024: castclass  A
IL_0029: call       A Process(IServiceFactory, A)/TestClass
IL_002e: ret        

注意:它从数组中加载实际的工厂对象。

此 IL 生成 InvalidProgramException。但是,如果我可以将静态方法转换为实例方法并在 TestClass 实例中执行调用,它就可以正常工作。

不知道哪里错了

您似乎在堆栈中加载了太多内容。第一部分似乎不错(忽略它与您想要的效果不符):

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();

我不知道生成的方法参数是什么,因为您没有 post 它们。不管怎样,继续前进:

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 进行了注释。您可以看到,当您到达 return 指令时,堆栈中有两个值。 IL_001a 处的 ldloc.0 似乎是一个错误,不应该存在(此外,IL_0023-0024 可以用简单的 ldloc.0 代替,而不是重新加载 arg。 1 并将其转换为 A)。这可以解释为什么当它不是静态方法时它可以工作:堆栈上的附加对象被视为调用方法的对象,因此它被正确使用。

根据您生成的方法是否应该 return 一个值,您可能需要额外的 pop 来清除 TestClass.Process 的 return 值方法出栈。既然你说它作为实例方法工作,这听起来像是生成的方法 returns 一个值,所以你不需要 pop.