C#真正通过引用传递是通过引用传递吗?

时间:2018-11-15 10:35:40

标签: c# .net

void Method(ref int refArgument)
{
    refArgument = refArgument + 44;
}

int number = 1;
Method(ref number);
Console.WriteLine(number);

内幕之下,真正发生了什么?

是否将内存地址传递给方法/函数并更改存储在该内存地址中的值?

OR

它创建一个新的内存地址并将值存储在该新创建的地址中,并将变量(数字)指向新的内存地址吗?

哪个是?

我的直觉是第一个,因为C#中的原始数据类型是struct,因此它们将始终按值传递

1 个答案:

答案 0 :(得分:5)

如果我们查看您的代码段的IL代码:

IL_0000:  nop         
IL_0001:  nop         
IL_0002:  ldc.i4.1    
IL_0003:  stloc.0     // number
// Loads the address of the local variable at a specific index onto the evaluation stack, short form. see: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldloca_s?view=netframework-4.7.2
IL_0004:  ldloca.s    00 // number
IL_0006:  call        g__Method|0_0
IL_000B:  nop         
IL_000C:  ldloc.0     // number
IL_000D:  call        System.Console.WriteLine
IL_0012:  nop         
IL_0013:  ret         

g__Method|0_0:
IL_0000:  nop   
// ldarg.0 called twice: 1. for ldind.i4 and 2. to store the result back to the memory location in stind.i4      
IL_0001:  ldarg.0     
IL_0002:  ldarg.0     
// Loads a value of type int32 as an int32 onto the evaluation stack indirectly. see: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldind_i4?view=netframework-4.7.2
// --> It used the passed intptr
IL_0003:  ldind.i4    
IL_0004:  ldc.i4.s    2C 
IL_0006:  add        
// Stores a value of type int32 at a supplied address. see: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.stind_i4?view=netframework-4.7.2
IL_0007:  stind.i4    
IL_0008:  ret         

就这样:

  1. ldind.i4从提供的内存地址中加载值并将其压入堆栈
  2. ldc.i4.s 2C将44加载到堆栈上
  3. add是否将堆栈的两个元素相加
  4. stind.i4将加法结果存储回内存地址