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

Getting value from top of IL stack using IL Emit

我有一个LocalBuilder,它本质上是一个数组。我可以在 IL 中很好地使用它,并且可以使用 OpCodes.Ldlen 加载它的长度。我只是想知道,是否有任何方法可以获取从堆栈顶部到某个实际变量的长度。我正在寻找类似

的东西
int lengthVariable = 0;

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

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

编辑:我在这里要做的是

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

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

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


经过评论中的讨论,似乎该言论

I know I can write a for loop in IL, but I was kind of avoiding writing branching statements of IL.

中题可能是可以克服的; foreach 并不是真的那么棘手 - 你所追求的最终 IL 是可以获得的 by decompiling existing code, which leaves the only really tricky bit the handling of labels for the actual branch targets - but that just means calling .DefineLabel() to declare them - you can use them as targets before you know where they'll be jumping to - and .MarkLabel() to position them (once only). It isn't quite direct IL (it uses an abstraction layer), but you can see this approach being used here - 特别要注意它使用 DefineLabel()提前,稍后在 MarkLabel.

标记目的地