反射发射堆栈和方法调用

5

有人可以解释一下在使用reflection.emit进行函数调用之前需要加载到堆栈中的内容吗?

我有一个非常简单的方法:

public static void Execute(string 1, string 2)

我希望能够动态生成以下类中的方法(忽略其余部分,我已经整理好了)。
public class Test{
    public string s1;

    public void Run(string s2)
    {
        MyOtherClass.Execute(s2,s1)
    }
}

我有一份以上测试的副本,供参考,我注意到在“调用”之前发出了以下操作码。

  1. ldarg_1
  2. ldarg_0
  3. ldfld

问题是为什么ldarg_0会出现在这里?我只需要2个参数进行调用,为什么CLR要求将ldarg_0推送到堆栈上?


你能提供周围的IL吗? - Simon Whitehead
2个回答

9

arg.0 包含 this,并且被 ldfld string Test:s1 要求,将 this.s1 推送到堆栈上。

.method public hidebysig instance void Run(string s2) cil managed
{
    .maxstack 8                                      // maximum stack size 8
    ldarg.1                                          // push argument s2
    ldarg.0                                          // push this
    ldfld string Test::s1                            // pop this, push this.s1
    call void MyOtherClass::Execute(string, string)  // call
    ret                                              // return
}

谢谢!我现在知道我错过了什么。 - Alwyn

2

如果方法不是静态的,你需要按照声明的顺序推送方法的参数和一个对象引用。在你的测试用例中,你正在访问一个成员字段 (s1),所以你需要使用 this 引用它。这就是 ldarg_0 提供的功能。接下来的 ldfld 弹出 this 引用并将字段的值推送到评估堆栈上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接