参考参数的 IL 差异

Difference in IL for ref paramters

我试图了解在 IL 级别处理按引用传递的参数和按值传递的参数的方式之间的区别。

下面是C#中的两个方法

    public static void TestRef(ref int x)
    {
        x++;
    }
    public static void Test(int x)
    {
        x++;
    }

按值传递的 IL 在下面,我知道它加载 arg,然后加载 int 常量 1 并将其添加并将其填回堆栈。

  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.1
  IL_0003:  add
  IL_0004:  starg.s    x
  IL_0006:  ret

通过引用传递的方法的 IL:

IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.0
  IL_0003:  ldind.i4
  IL_0004:  ldc.i4.1
  IL_0005:  add
  IL_0006:  stind.i4
  IL_0007:  ret

我不明白为什么会有两个 ldarg.0 语句。我假设 IL_0002/3 只是加载参数地址,然后加载该地址的参数值。

但是 IL_0001 呢?与 x =x+1 的左侧有关吗?

IL_0001: ldarg.0加载的地址将被在IL_0006: stind.i4的存储操作消耗。

msdn 告诉我们有关 stind.i4 操作码的信息:

The stack transitional behavior, in sequential order, is:

  1. An address is pushed onto the stack.

  2. A value is pushed onto the stack.

  3. The value and the address are popped from the stack; the value is stored at the address.

https://docs.microsoft.com/de-de/dotnet/api/system.reflection.emit.opcodes.stind_i4?view=netframework-4.8