使用 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 中创建一个循环,但我认为如果可能的话会方便得多。
编辑:我在这里要做的是
- 调用外部方法(returns数组)。
- 对该数组的所有元素执行一些操作。目前,我通过拥有数组的两个副本(IL 和非 IL)来做到这一点。使用非 IL 副本,我获取长度,然后执行该操作 n 次。
问题是我现在必须调用外部方法两次。我希望我可以从 IL 数组中获取长度,这样我就可以直接遍历它,而无需调用外部方法两次。我知道我可以在 IL 中编写 for 循环,但我有点避免编写 IL 的分支语句。
您不能像那样填充本地 lengthVariable
- 它在完全独立的范围/堆栈框架中运行。但是,您可以将方法(DynamicMethod
或 MethodBuilder
)更改为 return,然后为您的新方法创建一个委托作为 Func<int>
,并调用它。
那么你的最后一行将是 IL.Emit(Opcodes.Ret);
,到 return 本地堆栈上的单个值。或者,您可以将值存储到实例或静态字段中,使用 Opcodes.Stfld
或 Opcodes.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
.
标记目的地
我有一个LocalBuilder
,它本质上是一个数组。我可以在 IL 中很好地使用它,并且可以使用 OpCodes.Ldlen
加载它的长度。我只是想知道,是否有任何方法可以获取从堆栈顶部到某个实际变量的长度。我正在寻找类似
int lengthVariable = 0;
IL.Emit(OpCodes.Ldloc, arr);
IL.Emit(OpCodes.Ldlen);
IL.Emit(??????, lengthVariable);
我想得到这个变量,这样我就可以 运行 基于数组长度的循环。我知道我可以在 IL 中创建一个循环,但我认为如果可能的话会方便得多。
编辑:我在这里要做的是
- 调用外部方法(returns数组)。
- 对该数组的所有元素执行一些操作。目前,我通过拥有数组的两个副本(IL 和非 IL)来做到这一点。使用非 IL 副本,我获取长度,然后执行该操作 n 次。
问题是我现在必须调用外部方法两次。我希望我可以从 IL 数组中获取长度,这样我就可以直接遍历它,而无需调用外部方法两次。我知道我可以在 IL 中编写 for 循环,但我有点避免编写 IL 的分支语句。
您不能像那样填充本地 lengthVariable
- 它在完全独立的范围/堆栈框架中运行。但是,您可以将方法(DynamicMethod
或 MethodBuilder
)更改为 return,然后为您的新方法创建一个委托作为 Func<int>
,并调用它。
那么你的最后一行将是 IL.Emit(Opcodes.Ret);
,到 return 本地堆栈上的单个值。或者,您可以将值存储到实例或静态字段中,使用 Opcodes.Stfld
或 Opcodes.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
.