C#Emit IL - 将某个对象的值推送到堆栈上?

时间:2016-05-11 04:55:38

标签: c# .net reflection compiler-construction emit

我创建了一个动态方法,即:

class MyClass
{
    private void object _o = <whatever>;

    void CreateDynamicMethod()
    {
       DynamicMethod dm = new DynamicMethod("Test", ...);

       // emit various IL

       // need to push _o onto stack here
    }
}

第二条评论,我想将_o 当前的值推入堆栈。我不想推送_o的引用,因为它会随着构建动态方法而改变。

所以说_o = 5,我想推5,如果_o包含List,我想推送它,如果它包含一个字符串,我想推送字符串。

动态方法(Test)是一个静态方法,它显然不会有MyClass的this指针来获取字段。我甚至无法将它放在静态变量中,因为在执行Test()期间会访问它,而不是在我构建方法时。

即使我有这个指针,_o也不会在Test()执行时具有正确的值。

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您无法传递指针,因为它无效。但是,您可以传入句柄。我过去使用的一种技术是将整数值作为索引导入堆栈,作为某些静态可用资源的索引(如静态类中的字典,或网络资源,或其他),它将保存对象的值在将来这个方法将需要它。

这就是编译器按顺序执行虚方法调用的方式。它不知道它将在编译时调用哪个实例方法版本 - 它不知道。因此,表示方法的标记被压入堆栈而不是指向方法本身的指针。然后,该令牌将用于在运行时使用位于众所周知位置的资源执行vtable查找,并将令牌作为该资源的索引。

您需要完成任务的是您自己的vtable版本,并且您将使用整数作为令牌。 Ldc.i4.s是将所需的任何整数常量压入堆栈的IL指令。这是你的令牌:)在调用静态方法来检索你的对象之前将它推入堆栈。

确保在调用方法之前存储对象;)

有一些方法可以操纵堆栈来存储一个序列化的代理对象,然后该方法可以在调用它时进行反序列化。但如果我在这里解释一下,我会受到抨击。