参考 – 参数 – 堆栈或堆

这只是一个理论问题,但我无法得到一个好的答案:

如果我通过ref传递参数,则传递对象本身而不是副本。

这让我感到困惑:据我所知,每个方法都有自己的堆栈帧 – 内存,它们不能离开。 那么这是否意味着ref-Object被打包在Heap上并且有一个对这个参数的引用,或者该方法是否进入调用方法的堆栈并在那里工作?

如果我的问题令人困惑,我很抱歉,我基本上想知道如何保存ref类型以及它有什么影响。

伊迪丝:我想我并没有说清楚。 我理解值和refence类型的概念。 为了使它更容易,我尝试仅通过值类型来解释它,让我们说Int:

过程1通过传递Int ByVal调用Prodecure 2。 这个int在Prodecure 2的堆栈上有自己的内存,这意味着,在P2中改变这个值不会改变P1中的值,因为这两个值在每个堆栈中保存一次。

现在与byref相同:Prodecure 2不会保存Int的副本,但可以直接访问此值。 (在我的Oppinion中)有两种可能性来完成这项工作:

  1. int被打包在堆上,实际上在这个Int上有2个指针,但是由于它现在在堆上,所以在两个Prodecures上都可以看到值的变化。
  2. P2有类似的访问P1的堆栈,我认为这是不可能的,因为这意味着,堆栈生命周期不在Stone中设置。

这是否更清楚我的意思?

传递的参数是某个对象的地址。 该引用将在堆栈中传递,并与该方法的所有其他参数一起传递。

在调用方法之前,实际对象本身就存在于它所居住的任何地方。 那可能在堆栈中,它可能在堆中,没关系。 通过引用传递对象的行为不会导致它在内存中移动,例如从堆栈移动到堆,或从堆移动到堆栈。

虽然Servy已经正确地回答了这个问题,但是对于使用ref传递参数和通过值传递对象引用之间的区别,似乎存在很多混淆。 出于这个原因,我认为值得提供简短的说明。

假设以下简单类:

 class Player { public Player(int health) { Health = health; } public int Health { get; set; } } 

我们现在可以测试更新对象的属性并更改引用本身:

 static void Main(string[] args) { Player player = new Player(100); Console.WriteLine(player.Health); ChangeHealth(player); Console.WriteLine(player.Health); ChangeHealthByRef(ref player); Console.WriteLine(player.Health); ChangePlayer(player); Console.WriteLine(player.Health); ChangePlayerByRef(ref player); Console.WriteLine(player.Health); } static void ChangeHealth(Player player) { player.Health = 80; } static void ChangeHealthByRef(ref Player player) { player.Health = 60; } static void ChangePlayer(Player player) { player = new Player(40); } static void ChangePlayerByRef(ref Player player) { player = new Player(20); } 

输出:

 100 80 60 60 20 

ChangeHealth成功修改了player对象的Health属性。 ChangeHealthByRef还成功修改了player对象的Health属性。 因此,尽管ChangeHealth使用了引用的副本,但在两次调用中,您都可以看到player引用的对象可以被修改。

现在,这是我认为人们感到困惑的部分:

ChangePlayer创建一个新的Player对象,该对象修改传入的引用副本 。 这意味着更改不会反映在调用代码中(即Health仍然= 60)。 ChangePlayerByRef也会创建一个新的Player对象,但这次它直接修改了引用 ,这意味着更改确实反映在调用代码中(即Health = 20)。