简体   繁体   English

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

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

This is my first attempt to generate IL from expression and I couldn't get it working.这是我第一次尝试从表达式生成 IL,但我无法让它工作。 I couldn't make a call to a static method using IL generator.我无法使用 IL 生成器调用静态方法。

My Class structure is我的班级结构是

public class TestClass
{
    public static A Process(IServiceFactory factory, A a)
    {
        a.Value = 40;
        return a;
    }
}

public class A
{
    public int Value { get; set; }
}

I need to generate IL which does this我需要生成执行此操作的 IL

a.Value = 10;
TestClass.Process(factory,a)

The IL code I managed to generate is我设法生成的 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        

Note: its loading the actual factory object from a array.注意:它从数组加载实际的工厂对象。

This IL generates InvalidProgramException.此 IL 生成 InvalidProgramException。 But if I can the static method to instance method and execute the call within the TestClass instance it works fine.但是,如果我可以将静态方法实例化并在 TestClass 实例中执行调用,它就可以正常工作。

Not sure where I have got it wrong不知道我哪里弄错了

It looks like you're loading too much stuff on the stack.看起来您在堆栈上加载了太多东西。 The first part seems fine (ignoring that it doesn't match your desired effect):第一部分看起来不错(忽略它与您想要的效果不符):

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

Roughly this is equivalent to the following C#:大致相当于以下 C#:

A a = (A) arg1;
a.Value = ((Func<int>)arg0[0]).Invoke();

I have no idea what the generated method args are as you didn't post them.我不知道生成的方法 args 是什么,因为您没有发布它们。 Anyway, moving on:无论如何,继续:

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   

I've annotated the IL with the state of the stack after each instruction.我在每条指令之后用堆栈的状态注释了 IL。 You can see that when you reach the return instruction, you have two values sitting on the stack.您可以看到,当您到达 return 指令时,堆栈上有两个值。 It seems that the ldloc.0 at IL_001a is a mistake and shouldn't be there (additionally, IL_0023-0024 could be replaced with a simple ldloc.0 rather than re-loading arg.1 and casting it to A ). ldloc.0处的 ldloc.0 似乎是一个错误,不应该存在(此外,IL_0023-0024 可以替换为简单的ldloc.0而不是重新加载 arg.1 并将其转换为A )。 This could explain why it works when it's not a static method: that additional object on the stack is treated as the object to invoke the method on, so it's consumed correctly.这可以解释为什么当它不是静态方法时它可以工作:堆栈上的附加对象被视为调用方法的对象,因此它被正确使用。

Depending on whether your generated method is supposed to return a value or not, you may need an additional pop to clear the return value of the TestClass.Process method off the stack.根据您生成的方法是否应该返回一个值,您可能需要额外的pop来从堆栈中清除TestClass.Process方法的返回值。 Since you said it worked as an instance method, that makes it sound like the generated method returns a value, so you won't need a pop .既然你说它作为一个实例方法工作,那么听起来就像生成的方法返回一个值,所以你不需要pop

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM