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

问题描述 投票:1回答:1

我有一个LocalBuilder,它本质上是一个数组。我可以在IL中使用它,也可以使用OpCodes.Ldlen加载它的长度。我只是想知道,是否有任何方法可以将长度从堆栈顶部移至某个实际变量。我正在寻找类似的东西

int lengthVariable = 0;

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

我想获取此变量,以便可以基于数组的长度运行循环。我知道我可以在IL中创建一个循环,但是我认为如果可能的话,它将更加方便。

编辑:我想在这里做的是

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

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

c# reflection cil reflection.emit
1个回答
0
投票

您不能像这样填充本地lengthVariable-它在完全独立的范围/堆栈框架中运行。但是,您可以将方法(DynamicMethodMethodBuilder)更改为return,然后将新方法的委托创建为Func<int>,然后调用它。

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


在评论中讨论之后,似乎这句话

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

问题上可能是可以克服的;foreach不是真的

十分棘手-您要获得的最终IL是可以获取的by decompiling existing code,只剩下真正的[[tricky位来处理实际分支目标的标签-但是这仅意味着调用.DefineLabel()声明它们-您可以将它们用作目标,然后知道它们将跳转到的位置-和.MarkLabel()放置它们(仅一次)。它不是direct IL(它使用抽象层),但是您可以看到here正在使用此方法-特别是,请注意,它提前使用DefineLabel(),并在以后标记目标在MarkLabel
© www.soinside.com 2019 - 2024. All rights reserved.