代码之家  ›  专栏  ›  技术社区  ›  Grimson

使用IL Emit从IL堆栈顶部获取值

  •  1
  • Grimson  · 技术社区  · 6 年前

    我有一个 LocalBuilder ,这实际上是一个数组。我可以很好地在IL中使用它,我可以使用 OpCodes.Ldlen . 我只是想知道,是否有任何方法可以将堆栈顶部到某个实际变量的长度。我在找一些像

    int lengthVariable = 0;
    
    IL.Emit(OpCodes.Ldloc, arr);
    IL.Emit(OpCodes.Ldlen);
    IL.Emit(??????, lengthVariable);
    

    我想得到这个变量,这样我就可以根据数组的长度运行一个循环。我知道我可以在IL中创建一个循环,但我认为如果可能的话,这样做会方便得多。

    编辑:我想在这里做的是

    • 调用外部方法(返回数组)。
    • 对该数组的所有元素执行一些操作。目前,我通过拥有两个数组副本(IL和non-IL)来实现这一点。使用非IL拷贝,我得到长度,然后执行n次操作。

    问题是我现在必须调用外部方法两次。我希望可以从IL数组中获取长度,这样就可以直接循环它,而不必调用外部方法两次。我知道我可以在IL中编写for循环,但我有点避免编写IL的分支语句。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Marc Gravell    6 年前

    无法填充本地 lengthVariable 就像那样-它在一个完全独立的作用域/堆栈框架中运行。但是,你可以改变你的方法( DynamicMethod MethodBuilder )到 返回 然后创建新方法的委托 Func<int> ,并调用它。

    那么你的最后一句台词是 IL.Emit(Opcodes.Ret); ,以返回本地堆栈上的单个值。或者,您可以将值存储到实例或静态字段中,使用 Opcodes.Stfld Opcodes.Stsfld .


    在评论中讨论之后,似乎

    我知道我可以在IL中编写for循环,但我有点避免编写IL的分支语句。

    在这个问题上是可以克服的; foreach 不是真的 所有这些都很棘手-你要找的最后一个IL是可以得到的 by decompiling existing code ,这使得 棘手的 为实际的分支目标处理标签-但这只意味着调用 .DefineLabel() 宣布他们 -在你知道它们会跳到哪里之前,你可以把它们当作目标 .MarkLabel() 给他们定位 (仅一次)。不是很好 直接的 IL(它使用一个抽象层),但是您可以看到正在使用这种方法 here -尤其要注意,它使用 DefineLabel() 提前,稍后标记目的地 MarkLabel .