Ref -参数-栈或堆

本文关键字:参数 Ref | 更新日期: 2023-09-27 17:49:47

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

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

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

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

伊迪丝:我想我没有说清楚。我理解值和引用类型的概念。为了更简单,我试着用一个值类型来解释它,比如Int:

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

现在与byref相同:过程2不保存Int的副本,但可以直接访问该值。(在我看来)有两种可能使这一工作:

  1. int被打包在堆上,实际上有2个指针这个Int,但是由于它现在在堆上,所以可以看到值的变化
  2. P2对P1的栈有一定的访问权限,这意味着我想这是不可能的,因为这意味着

这样能更清楚地表达我的意思吗?

Ref -参数-栈或堆

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

实际对象本身存在于调用该方法之前的位置。它可以在堆栈中,也可以在堆中,都无所谓。通过引用传递对象的行为不会导致对象在内存中被移动,比如从堆栈移动到堆,或者从堆移动到堆栈。

虽然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属性。因此,您可以看到,在这两个调用中,player所引用的对象都可以被修改,尽管ChangeHealth使用了引用的副本。

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

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

看一下这个问题的答案。

是否int ref parameter得到框?

也许它能帮助你。

谢谢