【问题标题】:C# Emit IL -- push value of some object onto stack?C# Emit IL -- 将某个对象的值推入堆栈?
【发布时间】:2016-05-11 04:55:38
【问题描述】:

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

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 current 的值压入堆栈。我不想推送 _o 的引用,因为它会随着我构建动态方法而改变。

假设 _o = 5,我想推入 5,如果 _o 包含一个列表,我想推那个,如果它包含一个字符串,我想推这个字符串。

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

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

有什么建议吗?

【问题讨论】:

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


    【解决方案1】:

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

    顺便说一下,编译器就是这样调用虚方法的。它不知道它会在编译时调用哪个版本的实例方法——它不知道。因此,表示方法的标记被压入堆栈,而不是指向方法本身的指针。然后,该令牌将用于在运行时使用已知位置的资源进行 vtable 查找,并将该令牌作为该资源的索引。

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

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

    有一些方法可以操作堆栈以存储序列化的代理对象,然后该方法可以在调用时反序列化。但是,如果我在这里解释如何,我会被激怒。

    【讨论】:

    • 你是说 GCHandle?在我的构建器代码中,我做了: object o = blah;带有 Opcodes.Ldc_I8 的 GCHandle.Alloc(o).ToIntPtr().ToInt64() 并没有崩溃,但是当我尝试在调试器中查看该值时,它无法访问内存错误。
    • @SledgeHammer - 不,我不是指 GC 句柄。我的意思是,存储对象并将其放在某个地方,一个数组,一个文件,等等。只需在某个地方有一个不错的静态方法,它接受一个 int 参数并将对象返回给您,然后您可以将该整数压入堆栈,知道您的静态方法将使用它作为稍后检索对象的键。换句话说——你可以在编译时压入堆栈的唯一对象是 int 或字符串文字的标记(你可以在其中一个中保存一个大对象!)
    • 是的,我之前确实有过静态方法/字典的想法,但它看起来很老套。哈哈。认为可能有更好的方法。猜不出来:(。谢谢。
    • 不要因为它是 hacky 而感到难过。从字面上看,虚拟方法已经实现了 40 年了 XD
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-27
    • 2023-03-12
    • 2018-12-30
    • 2017-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多