我想解释一下ldelem.ref
的作用。到目前为止,我已经将索引处的元素作为O加载到堆栈的顶部。
什么是索引?而且我认为类型O表示对象的类型将保持不变,例如,如果它是字符串,则它将保持字符串。
下面有一个我正在处理的代码的示例,我非常感谢您的理解。我评论了我所知道的。 所以在这种情况下
.locals init (
string V_0,
bool V_1,
string V_2,
bool V_3,
string V_4,
string V_5,
string V_6) // Declared 6 variables
.try
{
IL_0000: nop
IL_0001: nop // Does nothing - Debug build
IL_0002: ldarg.0 // Loads Argument 0 into memory/stack
IL_0003: ldc.i4.0 // Push Constant Value 0 into memory [Possibly from a variable]
IL_0004: ldelem.ref // Loads element at index onto the top of the stack as an O
IL_0005: stloc.0 // Pop value from stack into local Variable 0
IL_0006: ldloc.0 // Load local variable 0 onto stack
IL_0007: ldstr "del" // Loads string "del" in to top of stack
IL_000c: call bool [mscorlib]System.String::op_Equality(string, string) // Compares strings to see if they are equal
IL_0011: stloc.1 // Pop value from stack into local variable 1
IL_0012: ldloc.1 // Load local variable 1 onto the stack
IL_0013: brfalse.s IL_004e // If variable 1 is true keep going else jump to IL_004e
ldelem.ref
在这里做什么?
op_Equality
是否将字符串“ del”与变量0的内容进行比较?
我认为调用完成后,该操作的布尔值然后存储在堆栈的顶部,stloc.1
弹出该布尔值并将其存储在变量1中,然后加载ldloc.1
将该变量放到堆栈上,然后brfalse.s
检查Bool值,如果错误的“跳转”到IL_004e
,是这种情况吗?
答案 0 :(得分:2)
ldelem.ref将对数组元素的引用推入堆栈。这意味着它会复制它,而不是实际存储的引用。阅读System.Reflection.Emit documentation可能会有所帮助。
了解另一件事可能是,每条MSIL指令都需要堆栈中的N个值,其中N由所使用的特定指令确定(除其他外)。然后可以将其用于对事物进行心理分组以更容易理解。
IL_0002: ldarg.0
IL_0003: ldc.i4.0
IL_0004: ldelem.ref
ldelem.ref要求堆栈按顺序具有:数组引用,该数组的索引。它将弹出这些值,然后将引用推入堆栈。堆栈现在只包含一个东西。
IL_0005: stloc.0
现在将弹出堆栈上的唯一值,并将其放入本地存储中。堆栈是空的。
IL_0006: ldloc.0
IL_0007: ldstr "del"
IL_000c: call bool [mscorlib]System.String::op_Equality(string, string)
调用指令将在堆栈中弹出与参数一样多的项(包括实例,如果调用的方法是实例方法)。在这种情况下,它需要两个字符串参数,并将同时弹出局部变量的内容以及文字字符串“ del”。静态方法op_Equality返回布尔值,因此它将被压入堆栈。堆栈现在只包含一个东西。
IL_0011: stloc.1
现在将弹出堆栈上的唯一值,并将其放入本地存储中。堆栈是空的。
IL_0012: ldloc.1
IL_0013: brfalse.s IL_004e
然后加载该值并应用分支逻辑。
在C#中,MSIL所做的事情等同于以下内容:
if (array[0] == "del")
MSIL中的所有内容都是一种平衡行为。由于这是调试版本,因此与优化版本相比,nop指令可能更多,对本地语言的使用也更多(这对您有好处,因为您可以更轻松地进行操作)。