首页 > 解决方案 > C# 通过 ref 在引擎盖下传递它真的是通过引用传递吗?

问题描述

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

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

在引擎盖下,到底发生了什么?

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

或者

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

哪个是哪个?

我的预感是第一个,因为 C# 中的原始数据类型是结构,因此它们总是按值传递

标签: c#.net

解决方案


如果我们看一下您的代码段的 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将加法的结果存储回内存地址

推荐阅读