繁体   English   中英

做int参数获取框?

[英]Do int ref parameter get boxed?

说我有以下代码:

void Main()
{
    int a = 5;
    f1(ref a);
}

public void f1(ref int a)
{
    if(a > 7) return;
    a++;
    f1(ref a);
    Console.WriteLine(a);
}

输出是:

8 8 8 

即,当堆栈展开时,保持ref参数的值。

是否意味着将ref keyword添加到int parameter会导致它被装箱?
在递归调用期间,实际堆栈如何?

通过引用传递值类型会导致其在堆栈上的位置传递而不是值本身。 它与装箱拆箱无关。 这使得在递归调用期间堆栈的外观变得相当容易,因为每个调用都指向堆栈上的“相同”位置。

我认为很多混淆来自MSDN关于拳击和拆箱的段落

Boxing是给定进程的名称,其中值类型被转换为引用类型。 当您装入变量时,您将创建一个指向堆上的新副本的引用变量。 引用变量是一个对象,...

您可能会在两个不同的事物之间混淆: 1)按照您的意愿“转换”一个值类型来表示一个对象,根据定义它是一个引用类型

int a = 5;
object b = a; // boxed into a reference type

2) 通过引用传递值类型参数:

main(){
   int a = 5;
   doWork(ref a);
}
void doWork(ref int a)
{
    a++;
}

这是两件不同的事情。

创建一个可以提供不同结果的程序很容易,具体取决于ref int是否被装箱:

static void Main()
{
    int a = 5;
    f(ref a, ref a);
}

static void f(ref int a, ref int b)
{
    a = 3;
    Console.WriteLine(b);
}

你得到了什么? 我看到3印。

拳击涉及创建副本,所以如果ref a被装箱,输出将是5 相反,无论是ab是原来的引用a变量Main 如果它有帮助,你可以大多数(不完全)将它们视为指针。

添加现有答案如何实现:

CLR支持所谓的托管指针。 ref将托管指针传递给堆栈上的变量。 您还可以传递堆位置:

var array = new int[1];
F(ref array[0]);

您还可以将引用传递给字段。

这不会导致钉扎。 运行时(尤其是GC)可以理解托管指针。 它们是可重新定位的。 它们是安全可靠的。

你的Console.WriteLine(a); 将在递归完成后执行。 当int的值变为8时,递归完成。为了使其为8,它递​​归3次。 因此,在最后它将打印8然后将控制传递到上面的递归,其将再次打印8,因为变量被引用的值变为8。

还要检查ILDASM输出

.method public hidebysig static void  f1(int32& a) cil managed
{
  // Code size       26 (0x1a)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldind.i4
  IL_0002:  ldc.i4.7
  IL_0003:  ble.s      IL_0006
  IL_0005:  ret
  IL_0006:  ldarg.0
  **IL_0007:  dup**
  IL_0008:  ldind.i4
  IL_0009:  ldc.i4.1
  IL_000a:  add
  IL_000b:  stind.i4
  IL_000c:  ldarg.0
  IL_000d:  call       void ConsoleApplication1.Program::f1(int32&)
  IL_0012:  ldarg.0
  IL_0013:  ldind.i4
  IL_0014:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0019:  ret
} // end of method Program::f1

我认为你错误地说int参数被装箱了。 来自MSDN

Boxing是将值类型转换为类型对象或由此值类型实现的任何接口类型的过程

你在这里有一个通过引用传递的int参数,特别是它是一个通过引用传递的“值类型”。

有关详细信息,您可以参考Jon Skeet关于参数传递的出色解释

这不是拳击。

MSDN ref关键字文档中有明确的解释:

不要将引用传递的概念与引用类型的概念混淆。 这两个概念不尽相同。 无论是值类型还是引用类型,都可以通过ref修改方法参数。 通过引用传递时,没有值类型的装箱。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM